Wie finden Sie "It's" in einer Zeichenfolge, die nur "Is" enthält? Ich würde es für Sie beheben, aber ich weiß nicht, welche Konventionen für einfache Anführungszeichen / Escapezeichen in der von Ihnen verwendeten Sprache gelten.
Wenn ich mir die Daten ansehe, sehe ich, dass die andere Frage ein Duplikat dieser Frage ist. Schauen Sie sich auf jeden Fall meine Antwort an .
Ridgerunner
@ridgerunner: Ich stimme dafür, dies zu schließen, wie Sie vorgeschlagen haben. Es ist wahr, andere Frage ist neuer, aber es ist auch viel besser (hauptsächlich dank Ihrer Antwort).
Alan Moore
Antworten:
158
/"(?:[^"\\]|\\.)*"/
Arbeitet in The Regex Coach und PCRE Workbench.
Testbeispiel in JavaScript:
var s =' function(){ return " Is big \\"problem\\", \\no? "; }';var m = s.match(/"(?:[^"\\]|\\.)*"/);if(m !=null)
alert(m);
Macht Sinn. Einfaches Englisch: Zwei Anführungszeichen, die null oder mehr von "einem Zeichen, das kein Anführungszeichen oder ein Backslash ist" oder "einem Backslash, gefolgt von einem Zeichen" umgeben. Ich kann nicht glauben, dass ich nicht daran gedacht habe ...
Ajedi32
7
Ich werde mir antworten. =) (?:...)ist eine passive oder nicht erfassende Gruppe. Dies bedeutet, dass es später nicht mehr referenziert werden kann.
Magras
Nachdem ich viel gesucht und viel getestet habe, ist dies die wirkliche und einzige Lösung, die ich für dieses häufige Problem gefunden habe. Vielen Dank!
Cancerbero
9
Danke dafür. Ich wollte auch einfache Anführungszeichen finden, also passte ich es an /(["'])(?:[^\1\\]|\\.)*?\1/
Dieser stammt von nanorc.sample, das in vielen Linux-Distributionen erhältlich ist. Es wird zur Syntaxhervorhebung von Zeichenfolgen im C-Stil verwendet
Dies ist der einzige Satz, der für mich mit einer einzelnen, großen Zeichenfolge in Anführungszeichen von 1,5 KB mit 99 Escapezeichen funktioniert hat. Jeder andere Ausdruck auf dieser Seite ist in meinem Texteditor mit einem Überlauffehler fehlerhaft. Obwohl die meisten hier im Browser arbeiten, sollten Sie nur etwas beachten. Geige: jsfiddle.net/aow20y0L
Beejor
3
Weitere Informationen finden Sie in der Antwort von @ MarcAndrePoulin.
Shaunc
10
Die meisten der hier bereitgestellten Lösungen verwenden alternative Wiederholungspfade, dh (A | B) *.
Bei großen Eingaben können Stapelüberläufe auftreten, da einige Pattern-Compiler dies mithilfe der Rekursion implementieren.
So etwas wie das:
"(?:[^"\\]*(?:\\.)?)*"oder das von Guy Bedford bereitgestellte reduziert die Anzahl der Analyseschritte, wodurch die meisten Stapelüberläufe vermieden werden.
Durch das Abwechseln von \"und die .Übergänge über maskierte Anführungszeichen wird *?sichergestellt, dass Sie nicht über das Ende der Zeichenfolge in Anführungszeichen hinausgehen. Funktioniert mit .NET Framework RE-Klassen
Entnommen direkt von man perlreeinem Linux-System mit installiertem Perl 5.22.0. Als Optimierung verwendet dieser reguläre Ausdruck die "positive" Form von beiden +und *um ein Zurückverfolgen zu verhindern, da vorher bekannt ist, dass eine Zeichenfolge ohne abschließendes Anführungszeichen auf keinen Fall übereinstimmen würde.
Schön, aber zu flexibel für die Anfrage (passt zu einfachen Anführungszeichen ...). Und kann zu /".*?(?<!\)"/ vereinfacht werden, es sei denn, ich vermisse etwas. Oh, und einige Sprachen (z. B. JavaScript) verstehen leider keine negativen Lookbehind-Ausdrücke.
PhiLho
1
@PhiLho, nur die Verwendung eines einzelnen (? <! \\) würde bei maskierten Backslashes am Ende der Zeichenfolge fehlschlagen. Dies gilt jedoch für Look-Behinds in JavaScript.
Markus Jarderot
4
Dieser funktioniert perfekt auf PCRE und fällt nicht mit StackOverflow.
"(.*?[^\\])??((\\\\)+)?+"
Erläuterung:
Jede Zeichenfolge in Anführungszeichen beginnt mit Char : ";
Es kann eine beliebige Anzahl beliebiger Zeichen enthalten: .*?{Lazy match}; endet mit einem Nicht-Flucht-Charakter [^\\];
Anweisung (2) ist Lazy (!) Optional, da die Zeichenfolge leer sein kann (""). So:(.*?[^\\])??
Schließlich endet jede Zeichenfolge in Anführungszeichen mit Char ( "), es kann jedoch eine gerade Anzahl von Escape-Zeichenpaaren vorangestellt werden (\\\\)+. und es ist Greedy (!) optional: ((\\\\)+)?+{Greedy Matching}, weil die Zeichenfolge leer sein kann oder ohne Endpaare!
Dies ist eine sehr gute Lösung, [^\1]sollte aber durch eine ersetzt werden, .da es keine Anti-Back-Referenz gibt und es sowieso keine Rolle spielt. Die erste Bedingung wird immer übereinstimmen, bevor etwas Schlimmes passieren kann.
Seph Reed
@SephReed - Ersetzen [^\1]mit .würde effektiv diese Regex ändern ("|').*?\1und dann würde es passen "foo\"in "foo \" bar". Das heißt, es [^\1]ist schwer, tatsächlich zur Arbeit zu kommen. @ Mathiashansen - Sie sind besser dran mit dem unhandlichen und teuren (?!\1).(so wäre der gesamte Regex mit einer gewissen Effizienzbereinigung (["'])(?:\\.|(?!\1).)*+\1. Das +ist optional, wenn Ihr Motor es nicht unterstützt.
Adam Katz
2
Eine Option, die zuvor noch nicht angesprochen wurde, ist:
Kehren Sie die Zeichenfolge um.
Führen Sie den Abgleich für die umgekehrte Zeichenfolge durch.
Kehren Sie die übereinstimmenden Zeichenfolgen um.
Dies hat den zusätzlichen Vorteil, dass es möglich ist, entkommene offene Tags korrekt abzugleichen.
Nehmen wir an, Sie hatten die folgende Zeichenfolge. String \"this "should" NOT match\" and "this \"should\" match"
Hier \"this "should" NOT match\"sollte nicht abgestimmt werden und "should"sollte sein. Darüber hinaus this \"should\" matchsollte abgestimmt werden und \"should\"sollte nicht.
Zuerst ein Beispiel.
// The input string.const myString ='String \\"this "should" NOT match\\" and "this \\"should\\" match"';// The RegExp.const regExp =newRegExp(// Match close'([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))'+'((?:'+// Match escaped close quote'(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|'+// Match everything thats not the close quote'(?:(?!\\1).)'+'){0,})'+// Match open'(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))','g');// Reverse the matched strings.
matches = myString
// Reverse the string..split('').reverse().join('')// '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'// Match the quoted.match(regExp)// ['"hctam "\dluohs"\ siht"', '"dluohs"']// Reverse the matches.map(x => x.split('').reverse().join(''))// ['"this \"should\" match"', '"should"']// Re order the matches.reverse();// ['"should"', '"this \"should\" match"']
Okay, jetzt um die RegExp zu erklären. Dies ist der reguläre Ausdruck, der leicht in drei Teile zerlegt werden kann. Wie folgt:
# Part 1(['"]) # Match a closing quotation mark " or '(?!# As long as it's not followed by(?:[\\]{2})*# A pair of escape characters[\\]# and a single escape(?![\\])# As long as that's not followed by an escape)# Part 2((?:# Match inside the quotes(?:# Match option 1:
\1 # Match the closing quote(?=# As long as it's followed by(?:\\\\)*# A pair of escape characters
\\ # (?![\\])# As long as that's not followed by an escape)# and a single escape)|# OR(?:# Match option 2:(?!\1).# Any character that isn't the closing quote))*)# Match the group 0 or more times# Part 3(\1)# Match an open quotation mark that is the same as the closing one(?!# As long as it's not followed by(?:[\\]{2})*# A pair of escape characters[\\]# and a single escape(?![\\])# As long as that's not followed by an escape)
Man muss bedenken, dass Regexps keine Silberkugel für alles sind, was man braucht. Einige Dinge sind einfacher mit einem Cursor und linearen, manuellen Suchen zu tun. Eine CFL würde den Trick ziemlich trivial machen, aber es gibt nicht viele CFL-Implementierungen (afaik).
Bei Regexpal herumgespielt und am Ende diesen Regex erhalten: (Frag mich nicht, wie es funktioniert, ich verstehe kaum, obwohl ich es geschrieben habe lol)
Ich hatte ein ähnliches Problem beim Versuch, Zeichenfolgen in Anführungszeichen zu entfernen, die das Parsen einiger Dateien beeinträchtigen könnten.
Am Ende hatte ich eine zweistufige Lösung, die jeden verschlungenen regulären Ausdruck übertrifft, den Sie sich vorstellen können:
line = line.replace("\\\"","\'");// Replace escaped quotes with something easier to handle
line = line.replaceAll("\"([^\"]*)\"","\"x\"");// Simple is beautiful
Einfacher zu lesen und wahrscheinlich effizienter.
Wenn Ihre IDE IntelliJ Idea ist, können Sie all diese Kopfschmerzen vergessen und Ihren regulären Ausdruck in einer String-Variablen speichern. Wenn Sie ihn kopieren und in das doppelte Anführungszeichen einfügen, ändert er sich automatisch in ein für den regulären Ausdruck akzeptables Format.
Beispiel in Java:
String s ="\"en_usa\":[^\\,\\}]+";
Jetzt können Sie diese Variable in Ihrem regulären Ausdruck oder überall verwenden.
Antworten:
Arbeitet in The Regex Coach und PCRE Workbench.
Testbeispiel in JavaScript:
quelle
(?:...)
ist eine passive oder nicht erfassende Gruppe. Dies bedeutet, dass es später nicht mehr referenziert werden kann./(["'])(?:[^\1\\]|\\.)*?\1/
var s = ' my \\"new\\" string and \"this should be matched\"';
führt dieser Ansatz zu unerwarteten Ergebnissen.Dieser stammt von nanorc.sample, das in vielen Linux-Distributionen erhältlich ist. Es wird zur Syntaxhervorhebung von Zeichenfolgen im C-Stil verwendet
quelle
var s = ' my \\"new\\" string and \"this should be matched\"';
führt dieser Ansatz zu unerwarteten Ergebnissen." \"(\\\\.|[^\\\"])*\" "
Wie von ePharaoh bereitgestellt, lautet die Antwort
Verwenden Sie diese Option, damit die oben genannten Zeichenfolgen entweder auf einfache oder doppelte Anführungszeichen angewendet werden
quelle
Die meisten der hier bereitgestellten Lösungen verwenden alternative Wiederholungspfade, dh (A | B) *.
Bei großen Eingaben können Stapelüberläufe auftreten, da einige Pattern-Compiler dies mithilfe der Rekursion implementieren.
Java zum Beispiel: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993
So etwas wie das:
"(?:[^"\\]*(?:\\.)?)*"
oder das von Guy Bedford bereitgestellte reduziert die Anzahl der Analyseschritte, wodurch die meisten Stapelüberläufe vermieden werden.quelle
Durch das Abwechseln von
\"
und die.
Übergänge über maskierte Anführungszeichen wird*?
sichergestellt, dass Sie nicht über das Ende der Zeichenfolge in Anführungszeichen hinausgehen. Funktioniert mit .NET Framework RE-Klassenquelle
"\\"
var s = ' my \\"new\\" string and \"this should be matched\"';
/"(?:(?:\\"|[^"])*)"/g
Dies sollteEntnommen direkt von
man perlre
einem Linux-System mit installiertem Perl 5.22.0. Als Optimierung verwendet dieser reguläre Ausdruck die "positive" Form von beiden+
und*
um ein Zurückverfolgen zu verhindern, da vorher bekannt ist, dass eine Zeichenfolge ohne abschließendes Anführungszeichen auf keinen Fall übereinstimmen würde.quelle
sollte mit jeder Zeichenfolge in Anführungszeichen funktionieren
quelle
Dieser funktioniert perfekt auf PCRE und fällt nicht mit StackOverflow.
Erläuterung:
"
;.*?
{Lazy match}; endet mit einem Nicht-Flucht-Charakter[^\\]
;(.*?[^\\])??
"
), es kann jedoch eine gerade Anzahl von Escape-Zeichenpaaren vorangestellt werden(\\\\)+
. und es ist Greedy (!) optional:((\\\\)+)?+
{Greedy Matching}, weil die Zeichenfolge leer sein kann oder ohne Endpaare!quelle
"(.*?[^\\])?(\\\\)*"
Hier ist eine, die sowohl mit "als auch mit" funktioniert, und Sie können am Anfang ganz einfach andere hinzufügen.
Es verwendet die Rückreferenz (\ 1), die genau mit der ersten Gruppe ("oder ') übereinstimmt.
http://www.regular-expressions.info/backref.html
quelle
[^\1]
sollte aber durch eine ersetzt werden,.
da es keine Anti-Back-Referenz gibt und es sowieso keine Rolle spielt. Die erste Bedingung wird immer übereinstimmen, bevor etwas Schlimmes passieren kann.[^\1]
mit.
würde effektiv diese Regex ändern("|').*?\1
und dann würde es passen"foo\"
in"foo \" bar"
. Das heißt, es[^\1]
ist schwer, tatsächlich zur Arbeit zu kommen. @ Mathiashansen - Sie sind besser dran mit dem unhandlichen und teuren(?!\1).
(so wäre der gesamte Regex mit einer gewissen Effizienzbereinigung(["'])(?:\\.|(?!\1).)*+\1
. Das+
ist optional, wenn Ihr Motor es nicht unterstützt.Eine Option, die zuvor noch nicht angesprochen wurde, ist:
Dies hat den zusätzlichen Vorteil, dass es möglich ist, entkommene offene Tags korrekt abzugleichen.
Nehmen wir an, Sie hatten die folgende Zeichenfolge.
String \"this "should" NOT match\" and "this \"should\" match"
Hier\"this "should" NOT match\"
sollte nicht abgestimmt werden und"should"
sollte sein. Darüber hinausthis \"should\" match
sollte abgestimmt werden und\"should\"
sollte nicht.Zuerst ein Beispiel.
Okay, jetzt um die RegExp zu erklären. Dies ist der reguläre Ausdruck, der leicht in drei Teile zerlegt werden kann. Wie folgt:
Dies ist in Bildform wahrscheinlich viel klarer: Erstellt mit Jex Regulex
Bild auf Github (JavaScript Regular Expression Visualizer). Entschuldigung, ich habe nicht den Ruf, Bilder aufzunehmen, daher ist es vorerst nur ein Link.
Hier ist eine Zusammenfassung einer Beispielfunktion, die dieses etwas fortgeschrittenere Konzept verwendet: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js
quelle
Man muss bedenken, dass Regexps keine Silberkugel für alles sind, was man braucht. Einige Dinge sind einfacher mit einem Cursor und linearen, manuellen Suchen zu tun. Eine CFL würde den Trick ziemlich trivial machen, aber es gibt nicht viele CFL-Implementierungen (afaik).
quelle
Eine umfangreichere Version von https://stackoverflow.com/a/10786066/1794894
Diese Version enthält auch
“
und Schließen”
)quelle
Bei Regexpal herumgespielt und am Ende diesen Regex erhalten: (Frag mich nicht, wie es funktioniert, ich verstehe kaum, obwohl ich es geschrieben habe lol)
quelle
Wenn es von Anfang an gesucht wird, kann das vielleicht funktionieren?
quelle
Ich hatte ein ähnliches Problem beim Versuch, Zeichenfolgen in Anführungszeichen zu entfernen, die das Parsen einiger Dateien beeinträchtigen könnten.
Am Ende hatte ich eine zweistufige Lösung, die jeden verschlungenen regulären Ausdruck übertrifft, den Sie sich vorstellen können:
Einfacher zu lesen und wahrscheinlich effizienter.
quelle
Wenn Ihre IDE IntelliJ Idea ist, können Sie all diese Kopfschmerzen vergessen und Ihren regulären Ausdruck in einer String-Variablen speichern. Wenn Sie ihn kopieren und in das doppelte Anführungszeichen einfügen, ändert er sich automatisch in ein für den regulären Ausdruck akzeptables Format.
Beispiel in Java:
Jetzt können Sie diese Variable in Ihrem regulären Ausdruck oder überall verwenden.
quelle