Javaの正規表現、パート1:パターンマッチングとPatternクラス

Javaの文字クラスとさまざまな文字列クラスは、パターンマッチングの低レベルのサポートを提供しますが、そのサポートは通常、複雑なコードにつながります。よりシンプルで効率的なコーディングのために、JavaはRegexAPIを提供しています。この2部構成のチュートリアルは、正規表現とRegexAPIの使用を開始するのに役立ちます。最初に、java.util.regexパッケージに含まれる3つの強力なクラスを解凍し、次にPatternクラスとその洗練されたパターンマッチング構造を調べます。

ダウンロードコードを取得するこのチュートリアルのサンプルアプリケーションのソースコードをダウンロードします。JavaWorld用にJeffFriesenによって作成されました。

正規表現とは何ですか?

正規表現としても知られ、正規表現または正規表現は、その文字列であるパターン(テンプレート)の文字列のセットを記述する。パターンは、どの文字列がセットに属するかを決定します。パターンは、リテラル文字とメタ文字で構成されます。これらは、リテラルの意味ではなく、特別な意味を持つ文字です。

パターンマッチングは、テキストを検索して、一致、または正規表現のパターンに一致する文字列を識別するプロセスです。Javaは、RegexAPIを介したパターンマッチングをサポートしています。APIは、、、およびの3つのクラスPatternで構成され、すべてパッケージに含まれています。MatcherPatternSyntaxExceptionjava.util.regex

  • Patternパターンとも呼ばれるオブジェクトは、コンパイルされた正規表現です。
  • Matcherオブジェクトまたはマッチャーは、パターンを解釈して文字シーケンス内の一致を見つけるエンジンです(クラスがjava.lang.CharSequenceインターフェイスを実装し、テキストソースとして機能するオブジェクト)。
  • PatternSyntaxException オブジェクトは、不正な正規表現パターンを記述します。

Javaは、そのjava.lang.Stringクラスのさまざまなメソッドを介したパターンマッチングのサポートも提供します。たとえば、呼び出し文字列がの正規表現と完全に一致する場合のみboolean matches(String regex)trueを返します。regex

便利な方法

舞台裏、matches()およびStringその他の正規表現指向の便利なメソッドは、正規表現APIの観点から実装されています。

RegexDemo

私が作成したRegexDemoJavaの正規表現とに位置して様々な方法を実証するためのアプリケーションPatternMatcherおよびPatternSyntaxExceptionクラスを。デモのソースコードは次のとおりです。

リスト1.正規表現のデモンストレーション

import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class RegexDemo { public static void main(String[] args) { if (args.length != 2) { System.err.println("usage: java RegexDemo regex input"); return; } // Convert new-line (\n) character sequences to new-line characters. args[1] = args[1].replaceAll("\\\\n", "\n"); try { System.out.println("regex = " + args[0]); System.out.println("input = " + args[1]); Pattern p = Pattern.compile(args[0]); Matcher m = p.matcher(args[1]); while (m.find()) System.out.println("Found [" + m.group() + "] starting at " + m.start() + " and ending at " + (m.end() - 1)); } catch (PatternSyntaxException pse) { System.err.println("Bad regex: " + pse.getMessage()); System.err.println("Description: " + pse.getDescription()); System.err.println("Index: " + pse.getIndex()); System.err.println("Incorrect pattern: " + pse.getPattern()); } } }

RegexDemomain()メソッドが最初に行うことは、コマンドラインを検証することです。これには2つの引数が必要です。最初の引数は正規表現であり、2番目の引数は正規表現と照合される入力テキストです。

\n入力テキストの一部として改行()文字を指定することもできます。これを実現する唯一の方法は、\文字の後に文字を指定することnです。main()この文字シーケンスをUnicode値10に変換します。

RegexDemoのコードの大部分はtry-catch構文にあります。tryブロックは、最初に指定の正規表現と入力テキストを出力した後、作成しPatternたオブジェクトその格納コンパイル済み正規表現。 (正規表現は、パターンマッチング中のパフォーマンスを向上させるためにコンパイルされます。)マッチャーはPatternオブジェクトから抽出され、残りがなくなるまで一致を繰り返し検索するために使用されます。このcatchブロックはさまざまなPatternSyntaxExceptionメソッドを呼び出して、例外に関する有用な情報を抽出します。その後、この情報が出力されます。

この時点で、ソースコードの動作について詳しく知る必要はありません。パート2でAPIを調べると、明らかになります。ただし、リスト1をコンパイルする必要があります。リスト1のコードを取得し、コマンドラインに次のように入力してコンパイルしますRegexDemo

javac RegexDemo.java

パターンとその構成

Pattern、Regex APIを構成する3つのクラスの最初のものは、正規表現のコンパイル済み表現です。PatternのSDKドキュメントには、さまざまな正規表現構造が記載されていますが、すでに熱心な正規表現ユーザーでない限り、ドキュメントの一部で混乱する可能性があります。何で数量と違い何貪欲消極的、および所有数量は?何で文字クラス境界マッチャ後方参照、および組み込みフラグ式は?これらの質問などについては、次のセクションで回答します。

リテラル文字列

最も単純な正規表現構造はリテラル文字列です。パターン一致を成功させるには、入力テキストの一部がこの構成のパターンと一致する必要があります。次の例を考えてみましょう。

java RegexDemo apple applet

この例appleでは、applet入力テキストのパターンに一致するものがあるかどうかを検出しようとします。次の出力は、一致を示しています。

regex = apple input = applet Found [apple] starting at 0 and ending at 4

出力には正規表現と入力テキストが表示され、apple内の一致が成功したことが示されますapplet。さらに、その一致の開始インデックスと終了インデックスをそれぞれ表示します:04。開始インデックスは、パターン一致が発生する最初のテキスト位置を識別します。終了インデックスは、一致する最後のテキストの場所を識別します。

ここで、次のコマンドラインを指定するとします。

java RegexDemo apple crabapple

今回は、開始インデックスと終了インデックスが異なる次の一致が得られます。

regex = apple input = crabapple Found [apple] starting at 4 and ending at 8

appletが正規表現でappleあり、入力テキストである逆のシナリオでは、一致するものがありません。正規表現全体が一致する必要があります。この場合、入力テキストにはtafterが含まれていませんapple

メタ文字

より強力な正規表現構造は、リテラル文字とメタ文字を組み合わせます。例えば、中a.b期間のメタ文字、( .)の間に表示される任意の文字を表すaとしますb。次の例を考えてみましょう。

java RegexDemo .ox "The quick brown fox jumps over the lazy ox."

この例で.oxは、正規表現およびThe quick brown fox jumps over the lazy ox.入力テキストとして指定します。RegexDemo任意の文字で始まり、で終わる一致をテキストで検索しますox。次の出力が生成されます。

regex = .ox input = The quick brown fox jumps over the lazy ox. Found [fox] starting at 16 and ending at 18 Found [ ox] starting at 39 and ending at 41

The output reveals two matches: fox and ox (with the leading space character). The . metacharacter matches the f in the first match and the space character in the second match.

What happens when we replace .ox with the period metacharacter? That is, what output results from specifying the following command line:

java RegexDemo . "The quick brown fox jumps over the lazy ox."

Because the period metacharacter matches any character, RegexDemo outputs a match for each character (including the terminating period character) in the input text:

regex = . input = The quick brown fox jumps over the lazy ox. Found [T] starting at 0 and ending at 0 Found [h] starting at 1 and ending at 1 Found [e] starting at 2 and ending at 2 Found [ ] starting at 3 and ending at 3 Found [q] starting at 4 and ending at 4 Found [u] starting at 5 and ending at 5 Found [i] starting at 6 and ending at 6 Found [c] starting at 7 and ending at 7 Found [k] starting at 8 and ending at 8 Found [ ] starting at 9 and ending at 9 Found [b] starting at 10 and ending at 10 Found [r] starting at 11 and ending at 11 Found [o] starting at 12 and ending at 12 Found [w] starting at 13 and ending at 13 Found [n] starting at 14 and ending at 14 Found [ ] starting at 15 and ending at 15 Found [f] starting at 16 and ending at 16 Found [o] starting at 17 and ending at 17 Found [x] starting at 18 and ending at 18 Found [ ] starting at 19 and ending at 19 Found [j] starting at 20 and ending at 20 Found [u] starting at 21 and ending at 21 Found [m] starting at 22 and ending at 22 Found [p] starting at 23 and ending at 23 Found [s] starting at 24 and ending at 24 Found [ ] starting at 25 and ending at 25 Found [o] starting at 26 and ending at 26 Found [v] starting at 27 and ending at 27 Found [e] starting at 28 and ending at 28 Found [r] starting at 29 and ending at 29 Found [ ] starting at 30 and ending at 30 Found [t] starting at 31 and ending at 31 Found [h] starting at 32 and ending at 32 Found [e] starting at 33 and ending at 33 Found [ ] starting at 34 and ending at 34 Found [l] starting at 35 and ending at 35 Found [a] starting at 36 and ending at 36 Found [z] starting at 37 and ending at 37 Found [y] starting at 38 and ending at 38 Found [ ] starting at 39 and ending at 39 Found [o] starting at 40 and ending at 40 Found [x] starting at 41 and ending at 41 Found [.] starting at 42 and ending at 42

Quoting metacharacters

To specify . or any metacharacter as a literal character in a regex construct, quote the metacharacter in one of the following ways:

  • Precede the metacharacter with a backslash character.
  • Place the metacharacter between \Q and \E (e.g., \Q.\E).

Remember to double each backslash character (as in \\. or \\Q.\\E) that appears in a string literal such as String regex = "\\.";. Don't double the backslash character when it appears as part of a command-line argument.

Character classes

We sometimes need to limit characters that will produce matches to a specific character set. For example, we might search text for vowels a, e, i, o, and u, where any occurrence of a vowel indicates a match. A character class identifies a set of characters between square-bracket metacharacters ([ ]), helping us accomplish this task. Pattern supports simple, negation, range, union, intersection, and subtraction character classes. We'll look at all of these below.

Simple character class

The simple character class consists of characters placed side by side and matches only those characters. For example, [abc] matches characters a, b, and c.

Consider the following example:

java RegexDemo [csw] cave

This example matches only c with its counterpart in cave, as shown in the following output:

regex = [csw] input = cave Found [c] starting at 0 and ending at 0

Negation character class

The negation character class begins with the ^ metacharacter and matches only those characters not located in that class. For example, [^abc] matches all characters except a, b, and c.

Consider this example:

java RegexDemo "[^csw]" cave

Note that the double quotes are necessary on my Windows platform, whose shell treats the ^ character as an escape character.

This example matches a, v, and e with their counterparts in cave, as shown here:

regex = [^csw] input = cave Found [a] starting at 1 and ending at 1 Found [v] starting at 2 and ending at 2 Found [e] starting at 3 and ending at 3

Range character class

The range character class consists of two characters separated by a hyphen metacharacter (-). All characters beginning with the character on the left of the hyphen and ending with the character on the right of the hyphen belong to the range. For example, [a-z] matches all lowercase alphabetic characters. It's equivalent to specifying [abcdefghijklmnopqrstuvwxyz].

Consider the following example:

java RegexDemo [a-c] clown

This example matches only c with its counterpart in clown, as shown:

regex = [a-c] input = clown Found [c] starting at 0 and ending at 0

Merging multiple ranges

You can merge multiple ranges into the same range character class by placing them side by side. For example, [a-zA-Z] matches all lowercase and uppercase alphabetic characters.

Union character class

The union character class consists of multiple nested character classes and matches all characters that belong to the resulting union. For example, [a-d[m-p]] matches characters a through d and m through p.

Consider the following example:

java RegexDemo [ab[c-e]] abcdef

This example matches a, b, c, d, and e with their counterparts in abcdef:

regex = [ab[c-e]] input = abcdef Found [a] starting at 0 and ending at 0 Found [b] starting at 1 and ending at 1 Found [c] starting at 2 and ending at 2 Found [d] starting at 3 and ending at 3 Found [e] starting at 4 and ending at 4

Intersection character class

The intersection character class consists of characters common to all nested classes and matches only common characters. For example, [a-z&&[d-f]] matches characters d, e, and f.

Consider the following example:

java RegexDemo "[aeiouy&&[y]]" party

シェルが&文字をコマンド区切り文字として扱うWindowsプラットフォームでは、二重引用符が必要であることに注意してください。

この例yは、次の対応する例とのみ一致しpartyます。

regex = [aeiouy&&[y]] input = party Found [y] starting at 4 and ending at 4