|
|
正規表現を使った置換 |
H.Kamifuji . |
正規表現ではターゲット文字列がマッチするかどうかだけではなく、マッチした部分を他の文字列で置換することができます。ここでは正規表現を使った置換と分割の方法を確認していきます。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2021/11)では、JDK-17.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 にアップされています。一部、上位互換について、見直しを行っていきます。 |
|
パターンにマッチした部分を他の文字列で置換する方法を確認していきます。 最初にマッチした部分を置換まずはパターンに最初にマッチした部分を指定の文字列に置換する方法を確認します。Matcherクラスで定義されているreplaceFirstメソッドを使います。replaceFirst public String replaceFirst(String replacement)パターンとマッチする入力シーケンスの部分シーケンスのうち、最初の部分シーケンスを指定された置換文字列に置き換えます。 このメソッドはまず、この正規表現エンジンをリセットします。次に、入力シーケンスを走査して、パターンとマッチする最初の文字列を検索します。パターンとマッチしない文字列は、結果文字列に直接追加されます。 パターンとマッチした文字列は、置換文字列に置換されて結果に追加されます。appendReplacement メソッドと同様に、前方参照された部分シーケンスへの参照が置換文字列に含まれる場合があります。 置換文字列内でバックスラッシュ (\) とドル記号 ($) を使用すると、それをリテラル置換文字列として処理した場合とは結果が異なる場合があります。ドル記号は、先に説明したとおり、前方参照された部分シーケンスへの参照として処理される場合があり、バックスラッシュは置換文字列内のリテラル文字をエスケープするのに使用されます。 正規表現 dog、入力 "zzzdogzzzdogzzz"、および置換文字列 "cat" を指定した場合、その表現の正規表現エンジン上でこのメソッドを呼び出すと、文字列 "zzzcatzzzdogzzz" が生成されます。 このメソッドを呼び出すと、この正規表現エンジンの状態が変わります。この正規表現エンジンを後続のマッチ操作で使用する場合は、最初に正規表現エンジンをリセットする必要があります。 パラメータ: replacement - 置換文字列 戻り値: 最初にマッチした部分シーケンスを置換文字列で置き換え、前方参照された部分シーケンスを必 要に応じて置換することによって構築された文字列 1番目の引数には置換したい文字列を指定して下さい。パターンに最初にマッチした部分を引数に指定した文字列で置換した結果を戻り値として返します。 次の例を見てください。 String str = "Orange is 100yen, Banana is 180yen."; String regex = "yen"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceFirst("YEN");最初にパターンにマッチした部分をreplaceFirstメソッドの引数である"YEN"に置き換えますので、結果として次の文字列を取得できます。 Orange is 100YEN, Banana is 180yen. マッチした部分を全て置換続いてパターンにマッチした部分を全て指定の文字列に置換する方法を確認します。Matcherクラスで定義されているreplaceAllメソッドを使います。replaceAll public String replaceAll(String replacement)パターンとマッチする入力シーケンスの部分シーケンスを、指定された置換文字列に置き換えます。 このメソッドはまず、この正規表現エンジンをリセットします。次に、入力シーケンスを走査して、パターンとマッチする文字列を検索します。パターンとマッチしない文字列は、結果文字列に直接追加されます。 パターンとマッチした文字列は、置換文字列に置換されて結果に追加されます。appendReplacement メソッドと同様に、前方参照された部分シーケンスへの参照が置換文字列に含まれる場合があります。 置換文字列内でバックスラッシュ (\) とドル記号 ($) を使用すると、それをリテラル置換文字列として処理した場合とは結果が異なる場合があります。ドル記号は、先に説明したとおり、前方参照された部分シーケンスへの参照として処理される場合があり、バックスラッシュは置換文字列内のリテラル文字をエスケープするのに使用されます。 正規表現 a*b、入力 "aabfooaabfooabfoob"、および置換文字列 "-" を指定した場合、その表現の正規表現エンジン上でこのメソッドを呼び出すと、文字列 "-foo-foo-foo-" が生成されます。 このメソッドを呼び出すと、この正規表現エンジンの状態が変わります。この正規表現エンジンを後続のマッチ操作で使用する場合は、最初に正規表現エンジンをリセットする必要があります。 パラメータ: replacement - 置換文字列 戻り値: マッチしたすべての部分シーケンスを置換文字列で置き換え、前方参照された部分シーケンスを必 要に応じて置換することによって構築された文字列 1番目の引数には置換したい文字列を指定して下さい。今度のメソッドではパターンにマッチした部分を全て引数に指定した文字列で置換した結果を戻り値として返します。 次の例を見てください。 String str = "Orange is 100yen, Banana is 180yen."; String regex = "yen"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceAll("YEN");パターンにマッチした部分を全てreplaceAllメソッドの引数である"YEN"に置き換えますので、結果として次の文字列を取得できます。 Orange is 100YEN, Banana is 180YEN. Stringクラスのメソッドここで紹介したメソッドはStringクラスで定義されている同名メソッドを使っても同じ結果を得ることができます。パターンに最初にマッチした部分を指定の文字列に置換するにはStringクラスで定義されているreplaceFirstメソッドを使います。 replaceFirst public String replaceFirst(String regex, String replacement)指定された正規表現に一致する、この文字列の最初の部分文字列に対し、指定された置換を実行します。 このフォームのメソッド呼び出し str.replaceFirst(regex, repl) では、次の式と正確に同じ結果が得られます。 Pattern.compile(regex).matcher(str).replaceFirst(repl) 置換文字列内でバックスラッシュ (\) とドル記号 ($) を使用すると、それをリテラル置換文字列として処理した場合とは結果が異なる場合があります。Matcher.replaceFirst(java.lang.String) を参照してください。必要に応じて、Matcher.quoteReplacement(java.lang.String) を使用して、これらの文字に特別な意味を持たせないようにしてください。 パラメータ: regex - この文字列との一致を判定する正規表現 replacement - 最初に一致するものに置き換えられる文字列 戻り値: 結果として得られる String 例外: PatternSyntaxException - 正規表現の構文が無効な場合 1番目の引数には正規表現のパターンの元となる文字列を指定します。そして2番目の引数には置換したい文字列を指定して下さい。パターンに最初にマッチした部分を引数に指定した文字列で置換した結果を戻り値として返します。 またパターンにマッチした部分を全て指定の文字列に置換するにはStringクラスで定義されているreplaceAllメソッドを使います。 replaceAll public String replaceAll(String regex, String replacement)指定された正規表現に一致する、この文字列の各部分文字列に対し、指定された置換を実行します。 このフォームのメソッド呼び出し str.replaceAll(regex, repl) では、次の式と正確に同じ結果が得られます。 Pattern.compile(regex).matcher(str).replaceAll(repl) 置換文字列内でバックスラッシュ (\) とドル記号 ($) を使用すると、それをリテラル置換文字列として処理した場合とは結果が異なる場合があります。Matcher.replaceAll を参照してください。必要に応じて、Matcher.quoteReplacement(java.lang.String) を使用して、これらの文字に特別な意味を持たせないようにしてください。 パラメータ: regex - この文字列との一致を判定する正規表現 replacement - 一致するものそれぞれに置き換えられる文字列 戻り値: 結果として得られる String 例外: PatternSyntaxException - 正規表現の構文が無効な場合 1番目の引数には正規表現のパターンの元となる文字列を指定します。そして2番目の引数には置換したい文字列を指定して下さい。パターンにマッチした全ての部分を引数に指定した文字列で置換した結果を戻り値として返します。 次の例を見てください。 String str = "Orange is 100yen, Banana is 180yen."; String regex = "yen"; String result = str.replaceAll(regex, "YEN");ターゲット文字列を表すStringクラスのオブジェクトに対してreplaceFirstメソッドまたはreplaceAllメソッドを実行して下さい。結果としてはMatcherクラスのメソッドを使った場合と同じ結果を得ることができます。 Orange is 100YEN, Banana is 180YEN. では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * 指定の文字列に置換 */ import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample1_1{ public static void main(String args[]){ String str = "Orange is 100yen, Banana is 180yen."; String regex = "yen"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result1 = m.replaceFirst("YEN"); System.out.println("replaceFirst"); System.out.println("before : " + str); System.out.println("after : " + result1); String result2 = m.replaceAll("YEN"); System.out.println("replaceAll"); System.out.println("before : " + str); System.out.println("after : " + result2); String result3 = str.replaceAll(regex, "YEN"); System.out.println("String.replaceAll"); System.out.println("before : " + str); System.out.println("after : " + result3); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Replace]$ javac JSample1_1.java [xxxxxxxx@dddddddddd Replace]$ java JSample1_1 replaceFirst before : Orange is 100yen, Banana is 180yen. after : Orange is 100YEN, Banana is 180yen. replaceAll before : Orange is 100yen, Banana is 180yen. after : Orange is 100YEN, Banana is 180YEN. String.replaceAll before : Orange is 100yen, Banana is 180yen. after : Orange is 100YEN, Banana is 180YEN. [xxxxxxxx@dddddddddd Replace]$ |
パターンにマッチした文字列を、置換する文字列の中から参照して利用することが可能です。まず置換する文字列として"$0"を指定すると、マッチした部分文字列全体になります。 次の例を見てください。 String str = "Orange is 100yen, Banana is 180yen."; String regex = "\\d.+?yen"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceFirst("_$0_");今回の場合、最初にパターンにマッチするのは"100yen"です。置換する文字列は"_$0_"となっており、"$0"がマッチした部分文字列全体となりますので、結果的に"_100yen_"に置き換わります。 Orange is 100YEN, Banana is 180yen. 続いて、パターンを括弧を使ってグループ化することで、グループ毎にマッチした部分を個別に取り出すことができます。(「パターン内の括弧毎にマッチした部分文字列を取得」を参照して下さい)。 グループ毎にマッチした部分文字列は、順に"$1"、"$2"と記述することで取り出すことができます。 次の例を見てください。 String str = "Orange is 100yen, Banana is 180yen."; String regex = "(\\d.+?)(yen)"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceFirst("$2_$1");今回の場合、最初にパターンにマッチするのは"100yen"です。この時、グループ1にマッチするのが"100"、グループ2にマッチするのが"yen"となります。置換する文字列は"$2_$1"となっていますので結果的に"yen_100"に置き換わります。 Orange is yen_100, Banana is 180yen. このように"$0"でマッチした部分文字列全体、"$1"、"$2"などでグループ毎にマッチした部分文字列を置換の文字列の中で参照することができます。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * パターン内の括弧毎にマッチした部分文字列を使って置換 */ import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample2_1{ public static void main(String args[]){ String str = "Orange is 100yen, Banana is 180yen."; String regex = "(\\d.+?)(yen)"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result1 = m.replaceAll("'$0'"); System.out.println("replaceAll(\"'$0'\")"); System.out.println("before : " + str); System.out.println("after : " + result1); String result2 = m.replaceAll("$2_$1"); System.out.println("replaceAll(\"$2_$1\")"); System.out.println("before : " + str); System.out.println("after : " + result2); String result3 = m.replaceAll("\\\\$1"); System.out.println("replaceAll(\"\\\\$1\")"); System.out.println("before : " + str); System.out.println("after : " + result3); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Replace]$ javac JSample2_1.java [xxxxxxxx@dddddddddd Replace]$ java JSample2_1 replaceAll("'$0'") before : Orange is 100yen, Banana is 180yen. after : Orange is '100yen', Banana is '180yen'. replaceAll("$2_$1") before : Orange is 100yen, Banana is 180yen. after : Orange is yen_100, Banana is yen_180. replaceAll("\\$1") before : Orange is 100yen, Banana is 180yen. after : Orange is \100, Banana is \180. [xxxxxxxx@dddddddddd Replace]$ |
前のページで確認したとおり、置換する文字列の中で"$0"や"$1"と記述すると特別な意味を持ちます。そこで置換する文字列の中で"$"を単なる文字として使いたい場合には"\"を使って"\$"と記述して下さい。 次の例を見てください。 String str = "Orange is 100dollar, Banana is 180dollar."; String regex = "(\\d.+?)dollar"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceFirst("\\$$1");今回の場合、最初にパターンにマッチするのは"100dollar"です。置換する文字列は"\\$$1"となっており、"\\$"が文字としての"$"であり、"$1"がグループ1にマッチした部分文字列となりますので、結果的に"$100"に置き換わります。 Orange is $100, Banana is 180doller. またエスケープに使用される"\"も置換する文字列の中で特別な意味を持つことになるので、単なる文字として"\"を使いたい場合も"\"を使って"\\"として下さい。 次の例を見てください。 tring str = "Orange is 100yen, Banana is 180yen."; String regex = "(\\d.+?)dollar"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceFirst("\\\\$1");今回の場合、最初にパターンにマッチするのは"100yen"です。置換する文字列は"\\\\$1"となっており、"\\\\"が文字としての"\"であり、"$1"がグループ1にマッチした部分文字列となりますので、結果的に"\100"に置き換わります。 Orange is \100, Banana is 180yen. パターンとしては"\\"ですが、Javaの文字列の中で"\"記号はエスケープして"\\"と記載する必要があるため、このパターンを文字列の中に記述する場合は"\"一つにつき"\\"となるので"\\\\"と記述する必要があります。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * 置換の時のエスケープ処理 */ import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample3_1{ public static void main(String args[]){ String str = "Orange is 100dollar, Banana is 180dollar."; String regex = "(\\d.+?)dollar"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); String result = m.replaceAll("\\$$1"); System.out.println("replaceAll(\"\\$$1\")"); System.out.println("before : " + str); System.out.println("after : " + result); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Replace]$ javac JSample3_1.java [xxxxxxxx@dddddddddd Replace]$ java JSample3_1 replaceAll("\$$1") before : Orange is 100dollar, Banana is 180dollar. after : Orange is $100, Banana is $180. [xxxxxxxx@dddddddddd Replace]$ |
|