プロジェクト

全般

プロフィール

Java正規表現

基本的な使い方

プログラミングのパターン

  • まず、正規表現のパターンを定義する(Pattern)
  • そのパターンに、照合したい文字列をぶつけた結果を生成(Matcher)
  • その結果を参照したり、置き換えしたり

APIメモ

Matcher

  • group() と、 group(0) とは同じ表現

事例

ファイル名の判定

複数の拡張子のいずれかに合致する

(?i:.*\\.(bmp|gif|jpg|jpeg|png))

  • 最初の(?i:正規表現)は、正規表現で大文字・小文字を識別しない(CASE_INSENSITIVE)を指定しています。CASE_INSENSITIVEの範囲を丸括弧で表します。
  • 次の.*\\.は、任意の文字が任意個数続いた後にピリオドがあることを指定しています。
  • (bmp|gif|jpg|jpeg|png)は、文字列がそれぞれbmpかgifかjpgかjpegかpngのいずれかに合致するを指定しています。

これで、指定した文字列が、大文字・小文字の区別なく複数の拡張子のいずれかに合致するかを判定できます。

区切り子で区切られた文字列の操作

パイプライン記号|で区切られた文字列

例えば、次のような文字列があり、そこから指定場所のカラムを取り出しや、置換といった処理をしたいとします。
READ|01|2021-12-25|321|EXIT

4番目のカラムをマッチさせる正規表現
^\\|(?:[^|]*\\|){3}([^|]*).*$

  • 行頭パイプライン記号で始まり、^\\|
    パイプライン記号は正規表現上で意味を持つので、バックスラッシュ\でエスケープします。Javaの文字列ではバックスラッシュがエスケープ文字に使われるので、バックスラッシュとして扱うために2つ重ねています\\
  • パイプ記号以外の文字列とパイプ記号が3回繰り返し、(?:[^|]*\\|){3}
    ここで、(?:正規表現)は、グループ化が前方参照(グループを番号付けして後で取り出す)の対象外となります。
    なお、文字クラス[]の中ではパイプライン記号はエスケープ不要です。
  • パイプ記号以外の文字列、[^|]*
  • その後は任意文字列が行末まで、.*$
var pattern = Pattern.compile("^\\|(?:[^|]*\\|){3}([^|]*).*$");
var match = pattern.matcher("|START|READ|01|2021-12-25|321|EXIT");
if (!match.matches()) return;
System.out.println(match.group(1));

実行すると、2021-12-25 が表示されます。

Matcherのmatchesを呼び出さずに group()メソッドを呼ぶと、IllegalStateExceptionが発行されます。

全てのカラムを参照する方法を探して(未解決)

次の正規表現でパイプライン記号で区切られた文字列を繰り返しマッチさせようとしました。

^\\|(?:([^|]*)\\|)+EXIT$

結果は、グループは1つしかなく、最後にマッチした文字列が照合されました。どうやら上書きされてしまうようです。
これは、正規表現の字面中には、前方参照対象のグループ化がひとつしかないので、1つしか参照できないということです。

ひとつずつ参照していく

次の正規表現でパイプライン記号に挟まれた文字列を1つ表現します。

\\|([^|]*)\\|

var p = Pattern.compile("\\|([^|]*)\\|");
var m = p.matcher("|START|READ|01|2021-12-25|321|EXIT");
while (m.find()) {
    System.out.println("合致全体: " + m.group());
    System.out.println("合致内のグループ: " + m.group(1));
}

実行結果は次の表示

合致全体: |START|
合致内のグループ: START
合致全体: |01|
合致内のグループ: 01
合致全体: |321|
合致内のグループ: 321


2年以上前に更新