Java 高度な文法 詳細な正規表現
1️⃣コンセプト
正規表現は、1 つ以上の文字シーケンスを検索、取得、置換するためのテキストベースのパターン マッチング方法。Java には、java.util.regex
パッケージ。この記事では、Javaの正規表現の構文やよく使う操作、裏技などを詳しく解説します。
2️⃣ 文法
正規表現は、特定の構文を使用してパターンを定義します。以下は、Java正規表現構文の主な要素です-
-
文字列
文字、数字、およびほとんどの句読点は、文字列として直接表現できます。たとえば、"abcde"
文字列「abcde」を表す場合、 -
文字クラス
文字クラスは、文字セット内の任意の文字と一致するために使用されます。このうち、角括弧([]
)は文字クラスの先頭と末尾を示します。たとえば、[abcd]
「a」、「b」、「c」、または「d」のいずれかと一致します。
文字クラスも範囲表記をサポートします。たとえば、[0-9]
は 0 ~ 9 のいずれかの数字を表します。たとえば、b と c を除く小文字 a ~ z のいずれか[a-z&&[^bc]]
を表すために -
事前定義文字クラス
事前定義文字クラスは、これらの文字の定義を短縮する、すでに定義されている文字クラスのセットです。一般的な事前定義された文字クラスをいくつか示します。\d
: 数字。に相当します[0-9]
。\D
: 数字以外の文字。に相当します[^0-9]
。\s
: 空白文字。スペース、タブ、改行を含む。\S
: 空白以外の文字。スペース、タブ、改行は含めないでください。\w
: 単語の文字。数字、文字、アンダースコアを含めます。に相当します[a-zA-Z0-9_]
。\W
: 単語以外の文字。数字、文字、アンダースコアは含めないでください。
-
量子
量子は、パターンが一致する回数を指定するために使用されます。一般的な量指定子をいくつか次に示します。*
: 先行する 0 文字以上の文字と一致します。たとえば、a*b
「b」、「ab」、「aab」などと一致させることができます。+
: 先行する 1 つ以上の文字と一致します。たとえば、a+b
「ab」、「aab」、「aaab」などと一致させることができます。?
: 先行する 0 または 1 文字と一致します。たとえば、a?b
「b」または「ab」に一致します。{n,m}
: 前にある少なくとも n 文字、最大 m 文字と一致します。たとえば、a{1,3}b
「ab」、「aab」、「aaab」に一致させることができます。{n}
: n 文字に正確に一致します。たとえば、a{2}b
「aab」と一致させることができます。{n,}
: 先行する少なくとも n 文字と一致します。たとえば、a{2,}b
「aab」、「aaab」、「aaaab」などと一致させることができます。
量指定子は、非貪欲なパターン マッチングにも使用できます。
?
可能な限り狭い範囲に一致させるために正規表現に含められますが、デフォルトでは可能な限り広い範囲に一致します。たとえば、a.+?b
「ab」、「acb」、「abbb」などと一致させることができます。 -
ロケーター ロケーターは
パターンの位置を指定します。以下に一般的なロケーターをいくつか示します。^
: 文字列の先頭。たとえば、^abc
「abc」で始まる文字列と一致します。$
: 文字列の終わり。たとえば、abc$
「abc」で終わる文字列と一致します。\b
: 単語の境界。たとえば、\bfoo\b
文字列内の「foo」と一致することはできますが、「foobar」や「football」などとは一致しません。
-
特殊文字
正規表現では、一部の文字には特別な意味があり、エスケープ文字 ( ) で表す必要があります\
。一般的な特殊文字をいくつか示します。.
: 改行を除く任意の 1 文字に一致します。|
: または演算子。たとえば、a|b
「a」または「b」と一致します。()
: グループ化演算子。部分式をグループとしてキャプチャし、グループの内容を表示できます。たとえば、(ab)*
0 個以上の連続する「ab」文字列に一致します。?imnsux
: 正規表現を指定するために使用される特別なトークン。たとえば、(?i)
大文字と小文字を区別しないことを意味します。
3️⃣ Java操作API
通常の Java の正規表現ベースの API には、さまざまな操作を実装するためのメソッドが多数用意されています。このうち、最も一般的な操作には、一致、検索、置換などがあります。
Javaクラス | 方法 | 効果 |
---|---|---|
パターン | boolean matches(String regex, CharSequence input) |
文字列が一致し、一致するかどうかを示すブール値を返します |
Pattern compile(String regex) |
指定された正規表現をパターンにコンパイルして返します。 | |
Matcher matcher(CharSequence input) |
指定された入力シーケンス内のパターンを検索します。一致に関する情報を取得するためにそのメソッドを使用できるマッチャー オブジェクトを返します。 | |
マッチャー | boolean find() |
ターゲット文字列内の正規表現に一致する次の部分文字列を検索します。一致する部分文字列が見つかったかどうかを示すブール値を返します。 |
int start() |
ターゲット文字列内の部分文字列の開始位置を取得します | |
int end() |
対象文字列内の部分文字列の終了位置を取得します | |
String group() |
部分文字列を取得する | |
String group(int group) |
キャプチャ グループに一致する文字列を取得します。キャプチャ グループは、括弧で囲まれた正規表現内の部分式です。 | |
String replaceFirst(String replacement) |
正規表現に一致するターゲット文字列内の最初の部分文字列を指定された文字列に置き換え、文字列を返します。 | |
String replaceAll(String replacement) |
正規表現に一致するターゲット文字列内のすべての部分文字列を指定された文字列に置き換え、その文字列を返します。 | |
弦 | String[] split(String regex) |
正規表現で一致したパターンに従って文字列を分割し、文字列配列を返します。 |
String replaceAll(String regex, String replacement) |
指定された正規表現に一致するこの文字列のすべての部分文字列を指定された文字列に置き換えます。 | |
String replaceFirst(String regex, String replacement) |
指定された正規表現に一致するこの文字列の最初の部分文字列を指定された文字列に置き換えます。 |
3.1 マッチング
Java のjava.util.regex.Patternクラスは、文字列一致操作のboolean matches(String regex, CharSequence input)
メソッド。このメソッドは文字列全体と一致し、一致したかどうかを示すブール値を返します。
matches()
メソッドを使用した例を次に示します。
import java.util.regex.*;
public class RegexDemo {
public static void main(String[] args) {
String pattern = ".*hello.*";
String input = "hello, world!";
boolean isMatch = Pattern.matches(pattern, input);
System.out.println(isMatch);
}
}
上記のコードは次のように出力します。
true
3.2 検索
Java のjava.util.regex.Matcherクラスは、正規表現に一致する文字列内の部分文字列を検索するためのメソッドをいくつか提供します。その中で、最も一般的に使用される方法にはfind()
、 と がgroup()
。
find()
このメソッドは、現在のターゲット文字列で正規表現に一致する次の部分文字列を検索し、一致する部分文字列が見つかったかどうかを示すブール値を返します。見つかった場合はstart()
、end()
および メソッドを使用して部分文字列の開始位置と終了位置を取得できます。この部分文字列には、group()
メソッド。find()
メソッドが一致する部分文字列をすべて見つけた場合、メソッドを再度呼び出すと false が返されます。
サンプルコードは次のとおりです。
import java.util.regex.*;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "you";
String input = "How are you? How have you been?";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
while (m.find()) {
System.out.println("Found match at index " + m.start() + ": " + m.group());
}
}
}
上記のコードは次のように出力します。
Found match at index 8: you
Found match at index 22: you
パターン内の複数の部分文字列を特定の順序で 1 つずつ照合する必要がある場合は、正規表現で「グループのキャプチャ」を使用できます。キャプチャ グループはブラケット パターンを使用して作成され、各グループには番号が付けられます。たとえば、次の正規表現では、To(d{2})
キャプチャ グループを作成し、それに 1 という番号を付けます。このグループは、「To」とそれに続く 2 つの連続する「d」文字シーケンスに一致します。
Matcher オブジェクトは、マッチング操作の状態情報を表します。find()
この情報には、 、start()
、end()
およびgroup()
メソッドを介してアクセスできます。その中で、find()
このメソッドは、ターゲット文字列内で次に一致する項目を見つけるために使用され、このメソッドはstart()
、前の一致した項目の開始位置と終了位置にアクセスするために使用され、メソッドは、指定されたグループの部分文字列を返すために使用されます。以前の一致アイテム。end()
group()
3.3 交換
Java の java.util.regex.Matcher クラスはreplaceFirst()
、replaceAll()
置換操作を実行するメソッドを提供します。
replaceFirst()
このメソッドは、正規表現に一致するターゲット文字列内の最初の部分文字列を指定された置換文字列で置き換え、結果の文字列を返します。例えば:
import java.util.regex.*;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "llo";
String input = "hello, world!";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
String output = m.replaceFirst("foo");
System.out.println(output);
}
}
上記のコードは次のように出力します。
hefoo, world!
replaceAll()
メソッドは、指定された置換文字列を使用して、ターゲット文字列内の正規表現に一致するすべての部分文字列を置換し、結果の文字列を返します。例えば:
import java.util.regex.*;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "l";
String input = "hello, world!";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
String output = m.replaceAll("x");
System.out.println(output);
}
}
上記のコードは次のように出力します。
hexxo, worxd!
3.4 分割
Java の java.lang.String クラスは、正規表現によって一致するパターンに従って文字列を分割し、文字列配列を返すことができるsplit()
メソッドを。
サンプルコードは次のとおりです。
import java.util.Arrays;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "\\s+";
String input = "apple banana cherry";
String[] tokens = input.split(pattern);
System.out.println(Arrays.toString(tokens));
}
}
上記のコードは次のように出力します。
["apple", "banana", "cherry"]
上記のコードでは、文字列を空白文字 (スペース、タブ、改行を含む)input
で、結果をtokens
配列に格納します。
4️⃣ ヒント
基本的な正規表現の構文と操作に加えて、Java の正規表現機能をより効果的に使用するのに役立つ実用的なヒントがいくつかあります。
4.1 プリコンパイルされた正規表現
同じ正規表現を複数回使用する必要がある場合は、それを Pattern オブジェクトにプリコンパイルできます。これにより、正規表現を使用するたびに再コンパイルする必要がなくなり、効率が向上します。
以下は、プリコンパイルされた正規表現を使用したサンプル コードです。
import java.util.regex.*;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "\\d+";
String input = "123-456-7890";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
while (m.find()) {
System.out.println(m.group());
}
}
}
上記のコードは次のように出力します。
123
456
7890
4.2 条件式の埋め込み
Java の正規表現は、他のプログラミング言語と同様の 3 項条件式もサポートしており、正規表現に条件文を埋め込むことができます。これは、特定の一致に別の置換文字列を適用するためによく使用されます。例えば:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "\\[(logged|critical)\\]: (.*?)\\n";
String input = "[logged]: Hello, world!\n[critical]: Error: Invalid input\n";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
while (m.find()) {
System.out.println("string = " + m.group());
System.out.println("string part 1 = " + m.group(1));
System.out.println("string part 2 = " + m.group(2));
String output = m.replaceAll(m.group(1).equals("logged") ? "$2" : "***" );
System.out.println("replaceAll result = " + output);
}
}
}
上記のコードは次のように出力します。
string = [logged]: Hello, world!
string part 1 = logged
string part 2 = Hello, world!
replaceAll result = Hello, world!Error: Invalid input
上記のコードでは、正規表現を使用して文字列内の特定のパターンに一致します。
正規表現全体の意味は、「[logged/critical]: (改行文字を除く任意の文字列)\n」のようなテキスト形式と一致することです。このうち、「[logged/critical]」は最初のキャプチャ グループに格納され、「(改行文字を除く任意の文字列)」は 2 番目のキャプチャ グループに格納されます。
次に、replaceAll()
このメソッド条件式を埋め込み、最初のキャプチャ グループの値に基づいて置換文字列が選択されます。
なぜこの結果になるのかを分析してみましょう。最初のループでは、m.group(1).equals("logged")
条件が満たされた場合に"$2"
分岐。これは、規則性を満たすすべての一致結果が 2 番目のキャプチャ グループの文字列に置き換えられることを意味します。そのため、置き換え後の結果は次のようになります。 : Hello, world!Error: Invalid input
。そして、次の while ループの判定が行われると、この時点で文字列が変更されており、規則性を満たす部分文字列がなくなっているので、ループは終了します。
4.3 ゼロ幅アサーションの使用
Java の正規表現は、「ゼロ幅アサーション」と呼ばれる特別な構文もサポートしています。ゼロ幅アサーションは、式を照合するときに位置を指定するために使用される非キャプチャ一致であり、特定の条件を満たす必要があります。一般的に使用されるゼロ幅アサーションには、正の先読みアサーション、負の先読みアサーション、正の後読みアサーション、および負の後読みアサーションが含まれます。
肯定的な先読みアサーションを使用するコード例を次に示します。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo {
public static void main(String[] args) {
String pattern = "\\w+(?=\\s+is)";
String input = "John is a man, and Mary is a woman.";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
while (m.find()) {
System.out.println(m.group());
}
}
}
上記のコードは次のように出力します。
John
Mary
上記のコードでは、正規表現を使用して、空白文字と「is」文字列が続く文字列内の単語を検索しました。ここで、 は(?=\\s+is)
、一致の後に空白文字と「is」文字列が続くことを制限する肯定的な先読みアサーションです。
5️⃣ 応用シナリオ
正規表現は文字列パターンを記述するために使用される言語であり、強力な一致および検索機能を備えています。これは多くのコンピューター プログラムやシステムで広く使用されており、その応用シナリオには次のものが含まれます。
-
テキスト検索/一致: 正規表現を使用して、特定の形式に従って電話番号、電子メール アドレス、ドメイン名などのテキスト内のパターンを検索または一致させることができます。
-
データ検証/検証: 正規表現を使用して、入力データがパスワードの強度、日付形式、ID 番号などの特定の形式やルールに準拠しているかどうかを検証できます。
-
リアルタイム ログ ファイル分析: 正規表現を使用して、監視する必要があるパターンに一致するリアルタイムで生成されたログ データを検索し、ログ ファイルの内容を分析できます。
-
エディター/IDE でのコードの検索と置換: エディターまたは IDE で正規表現を使用してコードの検索と置換を実行し、作業効率を向上させることができます。
正規表現は多くのプログラミング言語とオペレーティング システムにまたがることができ、Java、Python、Perl、JavaScript、C++、C# などの主流のプログラミング言語には正規表現のサポートが組み込まれています。つまり、正規表現は汎用性と柔軟性が高く、プログラムを書いたりテキストデータを加工したりする際によく使われます。