Regex Frage - Ein oder mehrere Räume außerhalb eines Zitats geschlossenen Textblock
Frage
Ich mag jedes Auftreten mit einem einzigen Raum von mehr als einen Raum ersetzen sein, aber keine Aktion in Text in Anführungszeichen nehmen.
Gibt es eine Möglichkeit, dies mit einem Java-Regex zu tun? Wenn ja, können Sie es bitte versuchen oder einen Tipp geben mir?
Lösung
Hier ist ein weiterer Ansatz verwendet, dass ein Look-Ahead, um festzustellen, dass alle Anführungszeichen nach der aktuellen Position kam in matched pairs.
text = text.replaceAll(" ++(?=(?:[^\"]*+\"[^\"]*+\")*+[^\"]*+$)", " ");
Bei Bedarf kann der Look-Ahead angepasst werden zu handhaben entkam Anführungszeichen in den genannten Abschnitten.
Andere Tipps
Beim Versuch, etwas zu entsprechen, die sonst in etwas enthalten sein kann, kann es hilfreich sein, einen regulären Ausdruck zu konstruieren, die beide übereinstimmt, wie folgt aus:
("[^"\\]*(?:\\.[^"\\]*)*")|( +)
Dies wird eine Zeichenfolge in Anführungszeichen oder zwei oder mehr Räume entsprechen. Da die beiden Ausdrücke kombiniert werden, wird es eine Zeichenfolge in Anführungszeichen oder zwei oder mehr Räume passen, aber keine Leerzeichen in Anführungszeichen. Mit diesem Ausdruck, müssen Sie jedes Spiel zu untersuchen, um festzustellen, ob es sich um eine Zeichenfolge in Anführungszeichen oder zwei oder mehr Räume und entsprechend handeln:
Pattern spaceOrStringRegex = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|( +)" );
StringBuffer replacementBuffer = new StringBuffer();
Matcher spaceOrStringMatcher = spaceOrStringRegex.matcher( text );
while ( spaceOrStringMatcher.find() )
{
// if the space group is the match
if ( spaceOrStringMatcher.group( 2 ) != null )
{
// replace with a single space
spaceOrStringMatcher.appendReplacement( replacementBuffer, " " );
}
}
spaceOrStringMatcher.appendTail( replacementBuffer );
Text in Anführungszeichen: Sind die Anführungszeichen innerhalb der gleichen Zeile oder mehrere Zeilen
?tokenize es und einen einzigen Raum zwischen Token emittieren. Eine schnelle Google für „Java tokenizer, die Anführungszeichen behandelt“ aufgedreht: diesen Link
YMMV
edit: SO nicht auf diesen Link gefallen hat. Hier ist die Google-Suche Link: google . Es war das erste Ergebnis.
Ich persönlich nicht verwenden Java, aber das RegExp könnte den Trick tun:
([^\" ])*(\\\".*?\\\")*
Der Versuch, den Ausdruck mit RegexBuddy, erzeugt es diesen Code, sieht gut zu mir:
try {
Pattern regex = Pattern.compile("([^\" ])*(\\\".*?\\\")*", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
for (int i = 1; i <= regexMatcher.groupCount(); i++) {
// matched text: regexMatcher.group(i)
// match start: regexMatcher.start(i)
// match end: regexMatcher.end(i)
// I suppose here you must use something like
// sstr += regexMatcher.group(i) + " "
}
}
} catch (PatternSyntaxException ex) {
// Syntax error in the regular expression
}
Zumindest scheint es in Python zu funktionieren:
import re
text = """
este es un texto de prueba "para ver como se comporta " la funcion sobre esto
"para ver como se comporta " la funcion sobre esto "o sobre otro" lo q sea
"""
ret = ""
print text
reobj = re.compile(r'([^\" ])*(\".*?\")*', re.IGNORECASE)
for match in reobj.finditer(text):
if match.group() <> "":
ret = ret + match.group() + "|"
print ret
Nachdem Sie den angegebenen Inhalt analysieren, führen Sie dies auf dem Rest, in loser Schüttung oder Stück für Stück nach Bedarf an:
String text = "ABC DEF GHI JKL";
text = text.replaceAll("( )+", " ");
// text: "ABC DEF GHI JKL"
Jeff, Sie auf dem richtigen Weg sind, aber es gibt ein paar Fehler im Code, nämlich: (1) Sie haben vergessen, die Anführungszeichen in den negierten Zeichenklassen zu entkommen; (2) Die Pars innerhalb der ersten Erfassungsgruppe sollten die Nicht-Erfassung Vielzahl haben; (3) Wenn der zweite Satz für den Fang von Pars nicht in einem Spiel teilnehmen, gibt group(2)
null, und Sie testen nicht dafür; und (4) Wenn Sie testen für zwei oder mehr Räume in dem regex anstelle von einem oder mehr , Sie brauchen nicht auf die Länge des Spiels später zu überprüfen. Hier ist der überarbeitete Code:
import java.util.regex.*;
public class Test
{
public static void main(String[] args) throws Exception
{
String text = "blah blah \"boo boo boo\" blah blah";
Pattern p = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|( +)" );
StringBuffer sb = new StringBuffer();
Matcher m = p.matcher( text );
while ( m.find() )
{
if ( m.group( 2 ) != null )
{
m.appendReplacement( sb, " " );
}
}
m.appendTail( sb );
System.out.println( sb.toString() );
}
}