it-swarm.com.de

Sonderzeichen in regulären Java-Ausdrücken umgehen

Gibt es in Java eine Methode oder eine Open-Source-Bibliothek, um ein Sonderzeichen (Metazeichen) mit Escape-Zeichen zu versehen (nicht in Anführungszeichen zu setzen), um es als regulären Ausdruck zu verwenden?

Dies wäre sehr nützlich, wenn Sie einen regulären Ausdruck dynamisch erstellen möchten, ohne dass Sie jeden einzelnen Charakter manuell entziehen müssen.

Stellen Sie sich beispielsweise einen einfachen Regex wie \d+\.\d+ vor, der Zahlen mit einem Dezimalzeichen wie 1.2 sowie den folgenden Code angibt:

String digit = "d";
String point = ".";
String regex1 = "\\d+\\.\\d+";
String regex2 = Pattern.quote(digit + "+" + point + digit + "+");

Pattern numbers1 = Pattern.compile(regex1);
Pattern numbers2 = Pattern.compile(regex2);

System.out.println("Regex 1: " + regex1);

if (numbers1.matcher("1.2").matches()) {
    System.out.println("\tMatch");
} else {
    System.out.println("\tNo match");
}

System.out.println("Regex 2: " + regex2);

if (numbers2.matcher("1.2").matches()) {
    System.out.println("\tMatch");
} else {
    System.out.println("\tNo match");
}

Es ist nicht überraschend, dass die Ausgabe des obigen Codes Folgendes ergibt:

Regex 1: \d+\.\d+
    Match
Regex 2: \Qd+.d+\E
    No match

Das heißt, regex1 stimmt mit 1.2 überein, regex2 (das "dynamisch" erstellt wird) jedoch nicht (es entspricht stattdessen der Literalzeichenfolge d+.d+).

Gibt es also eine Methode, die jedem Regex-Metazeichen automatisch entgeht?

Wenn in Java.util.regex.Pattern eine statische escape()-Methode vorhanden wäre, die Ausgabe von

Pattern.escape('.')

wäre der String "\.", aber 

Pattern.escape(',')

sollte nur "," erzeugen, da es kein Meta-Zeichen ist. Ähnlich,

Pattern.escape('d')

könnte "\d" erzeugen, da 'd' zur Bezeichnung von Ziffern verwendet wird (obwohl das Escaping in diesem Fall möglicherweise keinen Sinn ergibt, da 'd' wörtlich 'd' bedeuten könnte, was vom regex-Interpeter nicht als etwas anderes missverstanden würde, wie es im Fall der Fall wäre '.').

19
PNS

Gibt es in Java eine Methode oder eine Open-Source-Bibliothek, um ein Sonderzeichen (Metazeichen) mit Escape-Zeichen zu versehen (nicht in Anführungszeichen zu setzen), um es als regulären Ausdruck zu verwenden?

Ich bin nicht zu 100% sicher, dass Sie das hier fragen. Wenn Sie nach einer Möglichkeit suchen, Konstanten zu erstellen, die Sie in Ihren Regex-Mustern verwenden können, sollten Sie sie nur mit "\\" voranstellen, aber es gibt keine Funktion von Nice Pattern.escape('.'), die Ihnen dabei hilft.

Wenn Sie also versuchen, "\\d" (die Zeichenfolge \d anstelle eines Dezimalzeichens) abzugleichen, würden Sie Folgendes tun:

// this will match on \d as opposed to a decimal character
String matchBackslashD = "\\\\d";
// as opposed to
String matchDecimalDigit = "\\d";

Die 4 Schrägstriche in der Java-Zeichenfolge werden im Regex-Muster in zwei Schrägstriche umgewandelt. 2 umgekehrte Schrägstriche in einem Regex-Muster entsprechen dem umgekehrten Schrägstrich. Wenn Sie ein Sonderzeichen mit einem Backslash voranstellen, wird dieses Zeichen zu einem normalen Zeichen anstelle eines Sonderzeichens.

matchPeriod = "\\.";
matchPlus = "\\+";
matchParens = "\\(\\)";
... 

In Ihrem Beitrag verwenden Sie die Pattern.quote(string)-Methode . Sie wissen wahrscheinlich, dass dies Ihr Muster zwischen "\\Q" und "\\E" umschließt, sodass Sie eine Zeichenfolge zuordnen können, auch wenn ein spezielles Regex-Zeichen darin enthalten ist (+, ., \\d usw.).

23
Gray

Ich habe dieses Muster geschrieben:

Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]");

Und verwende es in dieser Methode:

String escapeSpecialRegexChars(String str) {

    return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0");
}

Dann können Sie es beispielsweise so verwenden:

Pattern toSafePattern(String text)
{
    return Pattern.compile(".*" + escapeSpecialRegexChars(text) + ".*");
}

Wir mussten das tun, weil wir nach dem Escape ein paar reguläre Ausdrücke hinzufügen. Wenn nicht, können Sie einfach \Q und \E verwenden:

Pattern toSafePattern(String text)
{
    return Pattern.compile(".*\\Q" + text + "\\E.*")
}
23
Ferran Maylinch

Der Regex-Matcher weiß nur, dass Sie nach einer Ziffer suchen, und nicht nach dem Buchstaben d, wenn Sie den Buchstaben (\d) mit einem Escapezeichen versehen. Um das Regex-Escape-Zeichen in Java einzugeben, müssen Sie es mit einem Escapezeichen versehen (aus \ wird \\). Es gibt also keine Möglichkeit, doppelte Backslashes für spezielle Regex-Zeichen einzugeben.

6
Attila

Die Pattern.quote(String s) macht sozusagen, was Sie wollen. Es lässt jedoch ein wenig zu wünschen übrig; es entgeht den einzelnen Zeichen eigentlich nicht, es umschließt den String nur mit \Q...\E.

Es gibt keine Methode, die genau das tut, wonach Sie suchen, aber die gute Nachricht ist, dass es eigentlich ziemlich einfach ist, alle Sonderzeichen in einem regulären Ausdruck Java) zu maskieren:

regex.replaceAll("[\\W]", "\\\\$0")

Warum funktioniert das? Nun, in der Dokumentation zu Pattern heißt es ausdrücklich, dass es zulässig ist, nicht-alphabetische Zeichen zu maskieren, die nicht unbedingt maskiert werden müssen:

Es ist ein Fehler, einen Backslash vor einem Buchstaben zu verwenden, der kein Escape-Konstrukt kennzeichnet. Diese sind für zukünftige Erweiterungen der Sprache für reguläre Ausdrücke reserviert. Ein Backslash kann vor einem nicht-alphabetischen Zeichen verwendet werden, unabhängig davon, ob dieses Zeichen Teil eines Konstrukts ohne Flucht ist.

Beispielsweise ist ; Kein Sonderzeichen in einem regulären Ausdruck. Wenn Sie es jedoch umgehen, interpretiert Pattern\; Weiterhin als ;. Hier noch ein paar Beispiele:

  • > Wird zu \>, Was > Entspricht.
  • [ Wird zu \[, Der maskierten Form von [
  • 8 Ist immer noch 8.
  • \) Wird zu \\\), Wobei es sich um die maskierten Formen von \ Und ( Handelt.

Hinweis: Der Schlüssel ist die Definition von "nicht alphabetisch", was in der Dokumentation wirklich "nicht - Wort" bedeutet "Zeichen oder Zeichen außerhalb des Zeichensatzes [a-zA-Z_0-9].

1
wheeler

Stimmen Sie mit Gray zu, da Ihr Muster möglicherweise sowohl Litrals (\ [ \]) als auch Metazeichen ([]) enthält. Mit einem Hilfsprogramm sollten Sie also zunächst allen Zeichen entgehen können und dann Metazeichen hinzufügen, die Sie in demselben Muster hinzufügen möchten.

1
nir

Verwenden Sie diese Utility-Funktion escapeQuotes(), um Zeichenfolgen zwischen Groups und Sets eines RegualrExpression zu ersetzen. 

Liste der zu entweichenden Regex-Literale <([{\^-=$!|]})?*+.>

public class RegexUtils {
    static String escapeChars = "\\.?![]{}()<>*+-=^$|";
    public static String escapeQuotes(String str) {
        if(str != null && str.length() > 0) {
            return str.replaceAll("[\\W]", "\\\\$0"); // \W designates non-Word characters
        }
        return "";
    }
}

In der Klasse Pattern dient das Backslash-Zeichen ('\') zur Einführung von Escape-Konstrukten. Das String-Literal "\(hello\)" ist unzulässig und führt zu einem Fehler bei der Kompilierung. Um mit dem String (hallo) übereinzustimmen, muss das String-Literal "\\(hello\\)" verwendet werden.

Beispiel: Zeichenfolge, die mit (hello) abgeglichen werden soll, und der reguläre Ausdruck mit einer Gruppe lautet (\(hello\)). Hier müssen Sie nur die übereinstimmende Zeichenfolge wie unten dargestellt umleiten. Test Regex online

public static void main(String[] args) {
    String matched = "(hello)", regexExpGrup = "(" + escapeQuotes(matched) + ")";
    System.out.println("Regex : "+ regexExpGrup); // (\(hello\))
}
0
Yash

benutzen

pattern.compile("\"");
String s= p.toString()+"yourcontent"+p.toString();

gibt das Ergebnis als yourcontent so wie es ist

0
kavita