2012-07-16 6 views
5

Ich habe eine Zeichenfolge wie folgt:Wie passt man etwas mit Regex, das nicht zwischen zwei Sonderzeichen ist?

a b c a b "a b" b a "a"

Wie passen ich jeden a, die von " nicht Teil eines Strings begrenzt ist? Ich will alles passen, die fett ist hier:

ein bc a b "ab" b ein "a"

Ich will diese Spiele ersetzen (oder besser gesagt entfernen Wenn Sie sie durch eine leere Zeichenfolge ersetzen, wird das Entfernen der in Anführungszeichen gesetzten Teile nicht funktionieren, da diese in der Zeichenfolge verbleiben sollen. Ich benutze Ruby.

+0

Ein Regex passt jeweils auf einen einzelnen Teilstring. Wie man einen Regex wiederholt, ist eine Eigenschaft der Hosting-Sprache. Welche Sprache verwendest du? – tripleee

+0

@triplee Rubin. –

Antwort

13

die Zitate Unter der Annahme, sind richtig ausgeglichen und es gibt keine Zitate entkommen, dann ist es einfach:

result = subject.gsub(/a(?=(?:[^"]*"[^"]*")*[^"]*\Z)/, '') 

Dies ersetzt all a s mit dem leeren String zurück, wenn und nur wenn es eine gerade Anzahl von ist zitiert vor der übereinstimmenden a.

Erläuterung:

a  # Match a 
(?=  # only if it's followed by... 
(?:  # ...the following: 
    [^"]*" # any number of non-quotes, followed by one quote 
    [^"]*" # the same again, ensuring an even number 
)*  # any number of times (0, 2, 4 etc. quotes) 
[^"]* # followed by only non-quotes until 
\Z  # the end of the string. 
)  # End of lookahead assertion 

Wenn Sie in Anführungszeichen entgangen Anführungszeichen (a "length: 2\"") haben kann, ist es immer noch möglich, wird aber komplizierter sein:

result = subject.gsub(/a(?=(?:(?:\\.|[^"\\])*"(?:\\.|[^"\\])*")*(?:\\.|[^"\\])*\Z)/, '') 

Dies ist im Wesentlichen die gleiche Regex wie oben, nur (?:\\.|[^"\\]) für [^"]:

(?:  # Match either... 
\\. # an escaped character 
|  # or 
[^"\\] # any character except backslash or quote 
)  # End of alternation 
ersetzen
+0

+1 Dies ist die Antwort –

+0

Wow, ein beeindruckender regulärer Ausdruck! Nahm mich eine Weile, aber jetzt verstehe ich, wie es funktioniert :) Warum der Downvote? –

0

Vollwertige Regex-Lösung für Regex-Liebhaber, ohne sich um die Leistung oder Code-Lesbarkeit zu kümmern.

Bei dieser Lösung wird davon ausgegangen, dass keine Escape-Syntax vorhanden ist (bei der Escape-Syntax wird a in "sbd\"a" als innerhalb der Zeichenfolge gezählt).

Pseudocode:

processedString = 
    inputString.replaceAll("\\".*?\\"","") // Remove all quoted strings 
       .replaceFirst("\\".*", "") // Consider text after lonely quote as inside quote 

Dann können Sie den Text, den Sie in der processedString wollen übereinstimmen. Sie können die 2. Ersetzung entfernen, wenn Sie Text nach dem Einzelthema als äußeres Zitat betrachten.

EDIT

In Ruby, die Regex in dem obigen Code würde

/\".*?\"/ 

mit gsub

und

/\".*/ 

verwendet werden mit sub verwendet


den Ersatz Problem zu beheben, ich bin mir nicht sicher, ob dies möglich ist, aber es lohnt sich versuchen:

  • Deklarieren Sie einen Zähler
  • Verwenden Sie die regex /(\"|a)/ mit gsub, und Versorgungsfunktion.
  • In der Funktion, wenn Übereinstimmung ist ", dann Zähler erhöhen und " als Ersatz (im Grunde keine Änderung). Wenn die Übereinstimmung a ist, überprüfen Sie, ob der Zähler gerade ist: wenn Sie sogar Ihre Ersatzzeichenfolge angeben; Ansonsten liefern Sie einfach alles, was zusammenpasst.
+0

Hat das etwas mit "a" zu tun, wie in der OP-Anforderung erwähnt? –

+0

@ ElRonnoco: Ja. Anstatt alles auf einmal zu tun, entferne ich einfach alle in Anführungszeichen gesetzten Zeichenfolgen und lasse nur nicht in Anführungszeichen gesetzte Teile in der 'bearbeiteten Zeichenfolge' zurück. Dann wird die Suche nach Text einfach sein. Meine Lösung hat jedoch eine Annahme. – nhahtdh

+0

Ah, die Idee ist, dass * dann * Sie den Ersatz von 'a's ... –

4

js-Coder, diese alte Frage wieder auferstehen, weil es eine einfache Lösung hatte, die nicht erwähnt wurde. (Gefunden Ihre Frage, während einige der Forschung für ein regex bounty quest tun.)

Wie Sie die Regex wirklich winzig sehen können, ist im Vergleich mit dem regulären Ausdruck in der akzeptierten Antwort: ("[^"]*")|a

subject = 'a b c a b " a b " b a " a "' 
regex = /("[^"]*")|a/ 
replaced = subject.gsub(regex) {|m|$1} 
puts replaced 

See this live demo

Referenz

How to match pattern except in situations s1, s2, s3

How to match a pattern unless...