Wie kann man "alles bis zu dieser Zeichenfolge" in einem regulären Ausdruck abgleichen?


514

Nehmen Sie diesen regulären Ausdruck : /^[^abc]/. Dies stimmt mit jedem einzelnen Zeichen am Anfang einer Zeichenfolge überein, mit Ausnahme von a, b oder c.

Wenn Sie ein Nachher hinzufügen *- /^[^abc]*/- fügt der reguläre Ausdruck weiterhin jedes nachfolgende Zeichen zum Ergebnis hinzu, bis er entweder ein a, oder b , oder erfüllt c.

Bei der Quellzeichenfolge stimmt "qwerty qwerty whatever abc hello"der Ausdruck beispielsweise mit überein "qwerty qwerty wh".

Aber was wäre, wenn ich die passende Zeichenfolge haben wollte? "qwerty qwerty whatever "

... Mit anderen Worten, wie kann ich alles auf die genaue Reihenfolge "abc" abstimmen (aber nicht einschließen) ?


Was meinst du damit match but not including?
Toto

5
Ich meine, ich möchte übereinstimmen "qwerty qwerty whatever "- ohne das "abc". Mit anderen Worten, ich möchte nicht, dass die resultierende Übereinstimmung vorliegt "qwerty qwerty whatever abc".
Callum

2
In Javascript können Sie nur do string.split('abc')[0]. Sicherlich keine offizielle Antwort auf dieses Problem, aber ich finde es einfacher als Regex.
Wylliam Judd

Antworten:


1020

Sie haben nicht angegeben, welche Regex-Variante Sie verwenden, aber dies funktioniert in einer der beliebtesten Versionen, die als "vollständig" angesehen werden können.

/.+?(?=abc)/

Wie es funktioniert

Der .+? Teil ist die ungierige Version von .+ (einer oder mehreren von irgendetwas). Wenn wir verwenden .+, passt der Motor im Grunde zu allem. Wenn sich dann noch etwas in der Regex befindet, wird es in Schritten zurückgehen und versuchen, dem folgenden Teil zu entsprechen. Dies ist das gierige Verhalten, das bedeutet, so viel wie möglich zu befriedigen .

Wenn Sie verwenden .+?, anstatt alle auf einmal abzugleichen und für andere Bedingungen (falls vorhanden) zurückzukehren, stimmt die Engine schrittweise mit den nächsten Zeichen überein, bis der nachfolgende Teil der Regex übereinstimmt (erneut, falls vorhanden). Dies ist das Ungierige , was bedeutet, dass es möglichst wenig zu befriedigen gibt .

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

Danach haben wir eine Behauptung mit einer Breite von Null und sehen uns um . Diese gruppierte Konstruktion entspricht dem Inhalt, zählt jedoch nicht als übereinstimmende Zeichen ( Breite Null ). Es wird nur zurückgegeben, wenn es sich um eine Übereinstimmung handelt oder nicht ( Behauptung ).(?={contents})

Mit anderen Worten /.+?(?=abc)/bedeutet der reguläre Ausdruck :

Ordnen Sie so wenig Zeichen wie möglich zu, bis ein "abc" gefunden wird, ohne das "abc" zu zählen.


12
Dies funktioniert wahrscheinlich nicht mit Zeilenumbrüchen, wenn sie erfasst werden sollen.
Einord

3
Was ist der Unterschied zwischen .+?und .*?
Robbie

4
@ robbie0630 +bedeutet 1 oder mehr, wobei *0 oder mehr bedeutet. Das Einschließen / Ausschließen des ?Willens macht es gierig oder nicht gierig.
Jinglesthula

2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby

4
Ich habe bemerkt , dass dies etwas , wenn das Muster Ihrer Suche wählen nicht für nicht vorhanden, stattdessen , wenn Sie verwenden ^(?:(?!abc)(?!def).)*Sie Kette Muster ausschließen Sie nicht wollen , und es wird immer noch greift alles nach Bedarf auch wenn das Muster nicht existiert
Karan Shishoo

122

Wenn Sie alles bis "abc" erfassen möchten:

/^(.*?)abc/

Erläuterung:

( )erfaßt den Ausdruck in den Klammern für den Zugriff mit $1, $2etc.

^ Spielanfang der Linie

.*stimme mit nichts überein, ?nicht gierig (stimme mit der erforderlichen Mindestanzahl von Zeichen überein) - [1]

[1] Der Grund, warum dies erforderlich ist, ist der folgende in der folgenden Zeichenfolge:

whatever whatever something abc something abc

Standardmäßig sind reguläre Ausdrücke gierig , was bedeutet, dass sie so gut wie möglich übereinstimmen. Daher /^.*abc/würde "was auch immer etwas abc etwas" entsprechen. Durch Hinzufügen des nicht gierigen Quantifizierers ?stimmt der Regex nur mit "was auch immer etwas" überein.


4
Danke, aber deines schließt den ABC in das Match ein. Mit anderen Worten, die resultierende Übereinstimmung ist "was auch immer etwas abc".
Callum

1
Können Sie erklären, was Sie letztendlich versuchen? Wenn Ihr Szenario wie folgt lautet: (A) Sie möchten, dass alles zu "abc" führt - verwenden Sie einfach Klammern um das, was Sie erfassen möchten. (B) Sie möchten den String mit dem "abc" abgleichen - Sie müssen den abc trotzdem überprüfen, damit er unabhängig davon Teil des regulären Ausdrucks sein muss. Wie können Sie sonst überprüfen, ob es dort ist?
Jared Ng

sedscheint weder nicht gieriges Matching noch Look-around ( (?=...)) zu unterstützen. Was kann ich sonst noch tun? Beispielbefehl: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"kehrt zurück two,three, FOUR FIVE, aber ich erwarte two,three...
CodeManX

1
@CoDEmanX Du solltest das wahrscheinlich als deine eigene Frage und nicht als Kommentar posten, zumal es speziell um sed geht. Um Ihre Frage zu beantworten: Vielleicht möchten Sie sich die Antworten auf diese Frage ansehen . Beachten Sie auch, dass in Ihrem Beispiel ein nicht gieriger, aufmerksamer Interpreter nur zurückgeben würde two, nicht two,three.
Jared Ng

3
Dies ist , wie EVERY regexp Antwort sollte aussehen - Beispiel und Erklärung aller Teile ...
jave.web

54

Wie @Jared Ng und @Issun betonten, wird der Schlüssel zum Lösen dieser Art von RegEx wie "alles mit einem bestimmten Wort oder Teilstring abgleichen" oder "alles nach einem bestimmten Wort oder Teilstring abgleichen" als "Lookaround" -Anweisungen mit null Länge bezeichnet . Lesen Sie hier mehr darüber.

In Ihrem speziellen Fall kann dies durch einen positiven Blick in die Zukunft gelöst werden: .+?(?=abc)

Ein Bild sagt mehr als tausend Worte. Siehe die detaillierte Erklärung im Screenshot.

Regex101 Screenshot


23
.+?(?=abc)Copy-Pastable Regex ist mehr wert.
Tom

Was ist mit dem Ausschluss führender Leerzeichen?
Royi

8

Was Sie brauchen, ist sich um die Behauptung zu kümmern .+? (?=abc).

Siehe: Lookahead und Lookbehind Zero-Length Assertions

Seien Sie sich bewusst, dass dies [abc]nicht dasselbe ist wie abc. In Klammern steht keine Zeichenfolge - jedes Zeichen ist nur eine der Möglichkeiten. Außerhalb der Klammern wird es zur Zeichenfolge.


7

Für Regex in Java und ich glaube auch an die meisten Regex-Engines, wenn Sie den letzten Teil einschließen möchten, funktioniert dies:

.+?(abc)

Zum Beispiel in dieser Zeile:

I have this very nice senabctence

Wählen Sie alle Zeichen bis "abc" aus und schließen Sie auch abc ein

Mit unserer Regex wird das Ergebnis sein: I have this very nice senabc

Testen Sie dies: https://regex101.com/r/mX51ru/1


4

Ich endete mit dieser Frage zum Stapelüberlauf, nachdem ich nach Hilfe gesucht hatte, um mein Problem zu lösen, fand aber keine Lösung dafür :(

Also musste ich improvisieren ... nach einiger Zeit gelang es mir, den regulären Ausdruck zu erreichen, den ich brauchte:

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, benötigte ich bis zu einem Ordner vor dem Ordner "grp-bps", ohne den letzten Bindestrich einzuschließen. Und es war erforderlich, mindestens einen Ordner nach dem Ordner "grp-bps" zu haben.

Bearbeiten

Textversion zum Kopieren und Einfügen (ändern Sie 'grp-bps' für Ihren Text):

.*\/grp-bps\/[^\/]+

6
Keine Textversion? 🙄
Kiradotee

2

Dies macht bei Regex Sinn.

  1. Das genaue Wort kann dem folgenden Regex-Befehl entnommen werden:

("(.*?)")/G

Hier können wir das genaue Wort global erhalten, das in die doppelten Anführungszeichen gehört. Zum Beispiel, wenn unser Suchtext lautet:

Dies ist das Beispiel für Wörter in doppelten Anführungszeichen

dann werden wir aus diesem Satz "doppelt zitiert".


Willkommen bei StackOverflow und vielen Dank für Ihren Versuch zu helfen. Es fällt mir jedoch schwer zu erkennen, wie dies dem in der Frage angegebenen Ziel hilft. Können Sie das näher erläutern? Können Sie es auf die angegebenen Beispiele anwenden? Sie scheinen sich auf den Umgang mit zu konzentrieren ", was mir für die Frage irrelevant erscheint.
Yunnosch

1
Hallo, ich habe erklärt, wie man das Wort oder die Sätze zwischen die Sonderzeichen bringt. Hier ist unsere Frage auch "alles bis zur Abfolge von Sonderzeichen". Also habe ich es mit doppelten Anführungszeichen versucht und es hier erklärt. Vielen Dank.
Ponmurugan Mohanraj

2

Auf Python:

.+?(?=abc) funktioniert für den einzeiligen Fall.

[^]+?(?=abc)funktioniert nicht, da Python [^] nicht als gültigen regulären Ausdruck erkennt. Damit der mehrzeilige Abgleich funktioniert, müssen Sie die Option re.DOTALL verwenden, zum Beispiel:

re.findall('.+?(?=abc)', data, re.DOTALL)

0

Ich glaube, Sie brauchen Unterausdrücke. Wenn ich mich recht erinnere, können Sie die normalen ()Klammern für Unterausdrücke verwenden.

Dieser Teil stammt aus dem grep-Handbuch:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

Tun Sie so etwas wie ^[^(abc)]sollte den Trick tun.


Entschuldigung, das funktioniert nicht. Das Setzen des ABC in Klammern scheint keinen Unterschied zu machen. Sie werden weiterhin als "a ODER b ODER c" behandelt.
Callum

-1

Das $markiert das Ende eines Strings, also sollte so etwas funktionieren: [[^abc]*]$Wo Sie nach etwas suchen, das in keiner Iteration von ENDET abc, aber es müsste am Ende sein

Auch wenn Sie eine Skriptsprache mit Regex (wie PHP oder JS) verwenden, verfügen diese über eine Suchfunktion, die stoppt, wenn sie zum ersten Mal auf ein Muster stößt (und Sie können Start von links oder Start von rechts oder mit PHP angeben). Sie können implodieren, um die Zeichenfolge zu spiegeln.


-6

Versuche dies

.+?efg

Abfrage:

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

Ausgabe :

hijklmn
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.