it-swarm.com.de

Regex zum Aufteilen einer Zeichenfolge mit Leerzeichen, wenn keine einfachen oder doppelten Anführungszeichen verwendet werden

Ich bin neu in regulären Ausdrücken und würde mich über Ihre Hilfe freuen. Ich versuche, einen Ausdruck zusammenzustellen, der die Beispielzeichenfolge unter Verwendung aller Leerzeichen aufteilt, die nicht in einfache oder doppelte Anführungszeichen eingeschlossen sind. Mein letzter Versuch sieht folgendermaßen aus: (?!") und funktioniert nicht ganz. Vor dem Zitat spaltet es sich auf.

Beispieleingabe: 

This is a string that "will be" highlighted when your 'regular expression' matches something.

Gewünschte Leistung:

This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something.

Beachten Sie, dass "will be" und 'regular expression' den Abstand zwischen den Wörtern beibehalten.

97
carlsz

Ich verstehe nicht, warum alle anderen so komplexe reguläre Ausdrücke oder langen Code vorschlagen. Im Wesentlichen möchten Sie zwei Arten von Dingen aus Ihrer Zeichenfolge ziehen: Zeichenfolgen, die keine Leerzeichen oder Anführungszeichen sind, und Zeichenfolgen, die mit einem Anführungszeichen beginnen und enden, wobei zwischen zwei Anführungszeichen keine Anführungszeichen stehen. Mit diesem regulären Ausdruck können Sie diese Dinge leicht zuordnen:

[^\s"']+|"([^"]*)"|'([^']*)'

Ich habe die Erfassungsgruppen hinzugefügt, weil die Zitate nicht in der Liste enthalten sein sollen.

Dieser Java-Code erstellt die Liste, fügt die Erfassungsgruppe hinzu, wenn sie übereinstimmt, um die Anführungszeichen auszuschließen, und fügt die allgemeine Regex-Übereinstimmung hinzu, wenn die Erfassungsgruppe nicht übereinstimmt (ein nicht angegebenes Word wurde gefunden).

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    if (regexMatcher.group(1) != null) {
        // Add double-quoted string without the quotes
        matchList.add(regexMatcher.group(1));
    } else if (regexMatcher.group(2) != null) {
        // Add single-quoted string without the quotes
        matchList.add(regexMatcher.group(2));
    } else {
        // Add unquoted Word
        matchList.add(regexMatcher.group());
    }
} 

Wenn es Ihnen nichts ausmacht, die Anführungszeichen in der zurückgegebenen Liste zu haben, können Sie viel einfacheren Code verwenden:

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    matchList.add(regexMatcher.group());
} 
219
Jan Goyvaerts

In StackOverflow gibt es mehrere Fragen, die dieselbe Frage in verschiedenen Kontexten mit regulären Ausdrücken behandeln. Zum Beispiel: 

UPDATE: Beispiel für einen regulären Ausdruck zur Verarbeitung von Zeichenfolgen mit und ohne Anführungszeichen. Ref: Wie kann ich einen String teilen, außer in Anführungszeichen?

m/('.*?'|".*?"|\S+)/g 

Getestet dies mit einem schnellen Perl-Snippet und die Ausgabe wurde wie nachstehend wiedergegeben. Funktioniert auch für leere Zeichenfolgen oder nur Whitespace-Zeichenfolgen, wenn sie zwischen Anführungszeichen stehen (nicht sicher, ob dies gewünscht wird oder nicht). 

This
is
a
string
that
"will be"
highlighted
when
your
'regular expression'
matches
something.

Beachten Sie, dass dies die Anführungszeichen selbst in die übereinstimmenden Werte einschließt. Sie können dies jedoch durch eine Zeichenfolge ersetzen oder die reguläre Ausdrücke so ändern, dass sie nicht enthalten sind. Ich lasse das jetzt als Übung für den Leser oder ein anderes Poster, da 2:00 Uhr zu spät ist, um sich mit regulären Ausdrücken zu beschäftigen;)

12
Jay

Wenn Sie in der Zeichenfolge mit Escapezeichen versehene Anführungszeichen zulassen möchten, können Sie Folgendes verwenden:

(?:(['"])(.*?)(?<!\\)(?>\\\\)*\1|([^\s]+))

Strings in Anführungszeichen sind Gruppe 2, einzelne Wörter ohne Anführungszeichen sind Gruppe 3.

Sie können es an verschiedenen Strings hier ausprobieren: http://www.fileformat.info/tool/regex.htm oder http://gskinner.com/RegExr/

5
mcrumley

Der Regex von Jan Goyvaerts ist die beste Lösung, die ich bisher gefunden habe, schafft aber auch leere (null) Übereinstimmungen, die er in seinem Programm ausschließt. Diese leeren Übereinstimmungen werden auch von Regex-Testern (z. B. rubular.com) angezeigt. Wenn Sie die Suche umdrehen (suchen Sie zuerst nach den zitierten Teilen und dann nach den durch Leerzeichen getrennten Wörtern), können Sie dies mit einmal tun:

("[^"]*"|'[^']*'|[\S]+)+
3
iRon
(?<!\G".{0,99999})\s|(?<=\G".{0,99999}")\s

Dies stimmt mit den Leerzeichen überein, die nicht in doppelte Anführungszeichen eingeschlossen sind . Ich muss min, max {0,99999} verwenden, da Java * und + in lookbehind nicht unterstützt.

2

Es ist wahrscheinlich einfacher, die Zeichenfolge zu durchsuchen, jeden Teil zu packen, statt ihn zu teilen.

Grund dafür ist, dass Sie es an den Leerzeichen vor und nach "will be" aufteilen können. Ich kann mir aber keine Möglichkeit vorstellen, den Abstand zwischen den Spalten eines Splits zu ignorieren.

(nicht Java)

string = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";

regex = "\"(\\\"|(?!\\\").)+\"|[^ ]+"; // search for a quoted or non-spaced group
final = new Array();

while (string.length > 0) {
    string = string.trim();
    if (Regex(regex).test(string)) {
        final.Push(Regex(regex).match(string)[0]);
        string = string.replace(regex, ""); // progress to next "Word"
    }
}

Das Erfassen einzelner Anführungszeichen kann auch zu Problemen führen:

"Foo's Bar 'n Grill"

//=>

"Foo"
"s Bar "
"n"
"Grill"
1

String.split() ist hier nicht hilfreich, da es keine Möglichkeit gibt, Leerzeichen in Anführungszeichen (nicht teilen) und solche außerhalb (geteilt) zu unterscheiden. Matcher.lookingAt() ist wahrscheinlich das, was Sie brauchen:

String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|('[^']+?')|([^\\s]+?))\\s++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")) ||
            (s.startsWith("'") && s.endsWith("'")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

was die folgende Ausgabe erzeugt:

0: "This"
5: "is"
8: "a"
10: "string"
17: "that"
22: "will be"
32: "highlighted"
44: "when"
49: "your"
54: "regular expression"
75: "matches"
83: "something."
1
Zach Scrivena

Ein paar hoffentlich hilfreiche Änderungen an Jans akzeptierter Antwort:

(['"])((?:\\\1|.)+?)\1|([^\s"']+)
  • Ermöglicht es, Anführungszeichen in Anführungszeichen zu setzen
  • Vermeidet die Wiederholung des Musters für das einfache und doppelte Anführungszeichen; Dies vereinfacht auch das Hinzufügen weiterer Anführungszeichen, falls erforderlich (auf Kosten einer weiteren Erfassungsgruppe).
1
pascals

Jans Ansatz ist großartig, aber hier ist noch einer für die Platte. 

Wenn Sie eigentlich wie im Titel erwähnt aufteilen wollten, die Anführungszeichen in "will be" und 'regular expression' beibehalten, können Sie diese Methode verwenden, die direkt aus Übereinstimmung (oder Ersetzung)) eines Musters besteht, außer in den Situationen s1, s2, s3 usw

Der Regex: 

'[^']*'|\"[^\"]*\"|( )

Die beiden linken Alternativen stimmen mit 'quoted strings' und "double-quoted strings" überein. Wir werden diese Spiele ignorieren. Auf der rechten Seite werden Leerzeichen in Gruppe 1 erfasst und erfasst, und wir wissen, dass es sich um rechte Felder handelt, da sie nicht mit den Ausdrücken auf der linken Seite übereinstimmen. Diese werden durch SplitHere ersetzt und dann in SplitHere aufgeteilt. Auch hier handelt es sich um einen echten Split-Fall, bei dem "will be" und nicht will be gewünscht wird.

Hier ist eine vollständig funktionierende Implementierung (siehe die Ergebnisse auf der Online-Demo ).

import Java.util.*;
import Java.io.*;
import Java.util.regex.*;
import Java.util.List;

class Program {
public static void main (String[] args) throws Java.lang.Exception  {

String subject = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
Pattern regex = Pattern.compile("\'[^']*'|\"[^\"]*\"|( )");
Matcher m = regex.matcher(subject);
StringBuffer b= new StringBuffer();
while (m.find()) {
    if(m.group(1) != null) m.appendReplacement(b, "SplitHere");
    else m.appendReplacement(b, m.group(0));
}
m.appendTail(b);
String replaced = b.toString();
String[] splits = replaced.split("SplitHere");
for (String split : splits) System.out.println(split);
} // end main
} // end Program
1
zx81

Ich mochte Marcus 'Ansatz, aber ich habe ihn so modifiziert, dass ich Text in der Nähe der Anführungszeichen zulassen und sowohl "als auch" Anführungszeichen unterstützen könnte. Zum Beispiel brauchte ich a = "irgendein Wert", um ihn nicht in [a =, "zu teilen. irgendein Wert "].

(?<!\\G\\S{0,99999}[\"'].{0,99999})\\s|(?<=\\G\\S{0,99999}\".{0,99999}\"\\S{0,99999})\\s|(?<=\\G\\S{0,99999}'.{0,99999}'\\S{0,99999})\\s"
1
Eric Woodruff

Das Folgende gibt ein Array von Argumenten zurück. Argumente sind die auf Leerzeichen aufgeteilten Variablen 'command', sofern sie nicht in einfachen oder doppelten Anführungszeichen stehen. Die Übereinstimmungen werden dann geändert, um die einfachen und doppelten Anführungszeichen zu entfernen.

using System.Text.RegularExpressions;

var args = Regex.Matches(command, "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'").Cast<Match>
().Select(iMatch => iMatch.Value.Replace("\"", "").Replace("'", "")).ToArray();

Ich bin ziemlich sicher, dass dies allein mit regulären Ausdrücken nicht möglich ist. Die Prüfung, ob sich in einem anderen Tag etwas befindet, ist eine Analyseoperation. Dies scheint das gleiche Problem zu sein wie beim Versuch, XML mit einem regulären Ausdruck zu parsen - es kann nicht korrekt ausgeführt werden. Sie können möglicherweise Ihr gewünschtes Ergebnis erzielen, indem Sie wiederholt einen nicht gierigen, nicht-globalen Regex anwenden, der mit den zitierten Zeichenfolgen übereinstimmt. Wenn Sie dann nichts anderes finden, teilen Sie ihn an den Leerzeichen auf ... die mehrere Zeichen enthalten Probleme, einschließlich der Verfolgung der ursprünglichen Reihenfolge aller Teilzeichenfolgen. Am besten schreiben Sie einfach eine wirklich einfache Funktion, die über die Zeichenfolge iteriert und die gewünschten Token herauszieht.

0
rmeador

Wenn Sie c # verwenden, können Sie verwenden

string input= "This is a string that \"will be\" highlighted when your 'regular expression' matches <something random>";

List<string> list1 = 
                Regex.Matches(input, @"(?<match>\w+)|\""(?<match>[\w\s]*)""|'(?<match>[\w\s]*)'|<(?<match>[\w\s]*)>").Cast<Match>().Select(m => m.Groups["match"].Value).ToList();

foreach(var v in list1)
   Console.WriteLine(v);

Ich habe speziell " | <(? [\ W\s] *)> " hinzugefügt, um hervorzuheben, dass Sie beliebige Zeichen angeben können, um Phrasen zu gruppieren. (In diesem Fall verwende ich <> zur Gruppierung.

Ausgabe ist:

This
is
a
string
that
will be
highlighted
when
your
regular expression 
matches
something random
0
Praveen Singh

Sie können dies auch versuchen:

    String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something";
    String ss[] = str.split("\"|\'");
    for (int i = 0; i < ss.length; i++) {
        if ((i % 2) == 0) {//even
            String[] part1 = ss[i].split(" ");
            for (String pp1 : part1) {
                System.out.println("" + pp1);
            }
        } else {//odd
            System.out.println("" + ss[i]);
        }
    }
0
Rakesh Sosa