Reguläre Ausdrücke in Java
Einführende Beispiele
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "abc.".replaceAll( "b", "d" )); }}transcript
adc.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "abc.".replaceAll( ".", "d" )); }}transcript
dddd
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "abc.".replaceAll( "\\.", "d" )); }}transcript
abcd
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "abc.".replaceAll( java.util.regex.Pattern.quote( "." ), "d" )); }}transcript
abcd
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "abc.".replaceAll( "(.)", "[$1]" )); }}transcript
[a][b][c][.]
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "abc.".replaceAll( "(.)", java.util.regex.Matcher.quoteReplacement( "[$1]" ))); }}transcript
[$1][$1][$1][$1]
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "alpha beta\ngamma".replaceAll( "\\s", "" )); }}transcript
alphabetagamma
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "alpha beta\ngamma".replaceAll( ".", "o" )); }}transcript
oooooooooo
ooooo
Die folgende Auflistung einiger Muster zeigt nicht alle Möglichkeiten regulärer Ausdrücke. Die Beschreibungen sind teilweise etwas zu kurz und daher unvollständig. Eine ausführlichere und genauere Beschreibung findet sich in der Dokumentation von Java SE.
http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
Wir schreiben reguläre Ausdrücke außerhalb von Java-String-Literalen ohne die Verdopplung des inversen Schrägstrichs, die bei Angabe des regulären Ausdrucks als Teil eines Java-String-Literalen notwendig ist. Es ist aber ein häufiger Flüchtigkeitsfehler, diese Verdopplung zu vergessen, also sollte darauf geachtet werden! Steht unten beispielsweise »\(«, so ist in einem String-Literal zu schreiben: »\\(«
- Muster für einzelne Zeichen
\d genau eine Dezimalziffer
\D genau ein Zeichen, das keine Dezimalziffer ist
\s genau ein Leerraumzeichen
\S genau ein Zeichen, das kein Lerraumzeichen ist
\w genau ein Wortzeichen
\W genau ein Zeichen, das kein Wortzeichen ist
. genau ein Zeichen, das kein Zeilenende ist
\( runde Klammer auf
\) runde Klammer zu
A Alle Buchstaben stehen für sich selbst
0 Alle Ziffern stehen für sich selbst
- Unäre Zirkumfixoperatoren
() ein Muster (das zwischen den Klammern)
- Unäre Postfixoperatoren
? kein oder ein Vorkommen des direkt voranstehenden Musters (greedy)
+ mindestens ein Vorkommen des direkt voranstehenden Musters (greedy)
{2,3} zwei bis drei Vorkommen des direkt voranstehenden Musters (greedy)
* beliebig viele Vorkommen des direkt voranstehenden Musters (greedy)
- Binäre Operatoren
| das linke oder das rechte Muster
- Zeichenmengen
[] genau eines der Zeichen in den eckigen Klammern, Beispiele:
[abc] genau eines der Zeichen »a«, »b« oder »c«
[a-d] genau eines der Zeichen »a«, »b«, »c« oder »d«
[^cx] genau ein Zeichen, das kein »c« oder »x« ist
[^] in Java leider nicht "ein beliebiges Zeichen"
Ein beliebiges Zeichen
Es gibt kein einzelnes Musterzeichen, das direkt für ein beliebiges Zeichen steht. Hierfür kann man aber eines der beiden folgenden Muster verwenden: »[\S\s]« oder ».|\n«.
ReplaceAll
new String( "alpha's" ).replaceAll( "'", "\\'" );
s.replace(("'"), ("\\'"))
=
s.replaceAll(Pattern.quote("'"), Matcher.quoteReplacement("\\'"));
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "2008-01-29 10:23:29.405".replaceAll
( "^(\\d{4})-(\\d{2})-(\\d{2}).*", "$2/$3/$1" )); }}transcript
01/29/2008
Main.java
class Hms
{ public int h; public int m; public int s;
public Hms( final java.lang.String hms )
{ this.h = java.lang.Integer.valueOf
( hms.replaceAll( "(\\d\\d):\\d\\d:\\d\\d", "$1" ));
this.m = java.lang.Integer.valueOf
( hms.replaceAll( "\\d\\d:(\\d\\d):\\d\\d", "$1" ));
this.s = java.lang.Integer.valueOf
( hms.replaceAll( "\\d\\d:\\d\\d:(\\d\\d)", "$1" )); }
int minus( final Hms other )
{ final int diff=( this.h - other.h )* 60 +( this.m - other.m );
return diff < 0 ? 24 * 60 + diff : diff; }}
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( new Hms( "01:00:00" ).minus( new Hms( "22:00:00" ))); }}transcript
180
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "start alpha beta alpha gamma alpha delta end".
replaceAll( "^(.*)alpha.*$", "$1" )); }}transcript
start alpha beta alpha gamma
Gesucht sind wohl die Ziffern in den innersten Klammern.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( "(((6)0.08(0))0.7(5))0.7(8(8)1.2(7))".replaceAll("(^|\\)).*?($|\\((?=\\d+\\)))", "" )); }}transcript
60587
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format
( "%15.0f\n%16.1f\n%17.3f\n%18.5f\n%17.3f\n%16.1f\n%15.0f\n",
0., 0., 0., 0., 0., 0., 0. ).replaceAll( "\\S", "*" )); }}transcript
- (Überraschung!)
Zitieren
Das folgende Beispiel zeigt das wörtliche Zitieren von Such- und Ersatztext in replaceAll. Es wäre aber nicht unbedingt nötig, weil genauso gut auch gleich replace verwendet werden könnte.
Main.java
class String
{ final java.lang.String string;
public String( final java.lang.String string )
{ this.string = string; }
public java.lang.String replaceAll
( final java.lang.String search,
final java.lang.String replace )
{ return this.string.replaceAll
( java.util.regex.Pattern.quote( search ),
java.util.regex.Matcher.quoteReplacement( replace )); }}
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( new String( "alpha's" ).replaceAll( "'", "\\'" )); }}System.out
alpha\'s
split
Die »split«-Methode der Klasse »java.lang.String« akzeptiert einen regulären Ausdruck. In einem solchen hat das Zeichen »|« beispielsweise eine besondere Bedeutung. Was kann man tun, wenn man immer nach wörtlichen Texten zerlegen will, und keine regulären Ausdrücke verwenden möchte? Das folgende Programm zeigt eine spezielle String-Klasse, mit einer split-Operation, die alle Zeichen wörtlich nimmt. Zentral dabei ist die Verwendung von »java.util.regex.Pattern.quote«.
Das folgende Programm definiert
Main.java
class String
{ final java.lang.String string;
public String( final java.lang.String string )
{ this.string = string; }public java.lang.String[] split
( final java.lang.String text )
{ return this.string.split
( java.util.regex.Pattern.quote( text )); }}public final class Main
{ public static void main( final java.lang.String[] args )
{ final String text = new String( "alpha|beta" );
final java.lang.String[] strings = text.split( "|" );
for( java.lang.String string : strings )
java.lang.System.out.println( string ); }}System.out
alpha
beta
matches
java.lang.System.out.println( "abc".matches( "^a" ) )
Compile and Match
Das vorherige Übersetzen eines Musters kann die Wiederverwendung beschleunigen und ist die Voraussetzung für eine Operationen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.util.regex.Pattern p =
java.util.regex.Pattern.compile( "(.*?)(?:(?<!\\?):|$)" );
final java.util.regex.Matcher m = p.matcher( "123:456?:789" );
while( m.find() )java.lang.System.out.println( m.group( 1 )); }}System.out
123
456?:789
Verneinungen
Es ist immer etwas schwierig, Verneinungen mit regulären Ausdrücken auszudrücken. Das folgende Beispiels findet Texte, die nicht mit ».dwg« enden, ohne die Verneinung dabei mit den Mitteln der Programmiersprache Java auszudrücken. (Dieses Beispiel geht auf eine Idee von Ralf Ullrich zurück.)
Main.java
class Test
{ final java.lang.String pattern;
public Test( final java.lang.String pattern )
{ this.pattern = pattern; }
public void text( final java.lang.String text )
{ java.lang.System.out.println
( text + " " +( text.matches( this.pattern ) ? "=" : "!" )+
"~ " + this.pattern ); }}
public final class Main
{ public static void main( final java.lang.String[] args )
{ Test test = new Test( ".*(?<!\\.dwg)" );
test.text( "abce.dwg" );
test.text( "abce.dwx" );
test.text( "abce.xwg" );
test.text( "ab.cd.fg" );
test.text( "abc.dwga" );
test.text( "abcdefgh" ); }}System.out
abce.dwg !~ .*(?<!\.dwg)
abce.dwx =~ .*(?<!\.dwg)
abce.xwg =~ .*(?<!\.dwg)
ab.cd.fg =~ .*(?<!\.dwg)
abc.dwga =~ .*(?<!\.dwg)
abcdefgh =~ .*(?<!\.dwg)