JavaでStringのリストの内容にマッチする正規表現オブジェクトを作る

小ネタ。

たとえば下記のようなStringのリストがあったとして、

List<String> strList = Arrays.asList("alpha", "beta", "gamma", "delta");

リストの文字列にマッチする正規表現を作りたいといった場合は下記のようにすればいいです。

// (alpha|beta|gamma|delta) 相当の正規表現を得る
Pattern strListRegexp = 
  Pattern.compile("((?!.)." + strList.stream().map(Pattern::quote).map("|"::concat).collect(Collectors.joining()) + ")");

以下解説。

  • .map("|"::concat) は文字列のリスト(ストリーム)の全要素の前に | をくっつけるものです。
  • Collectors.joining() は文字列のリスト(ストリーム)を、全部くっつけるものです。
  • そういうことで、基本は文字列のリストを | でつないだものを作っています。
    • 単純に | でリストを結合して () カッコで囲めばいいところを、 ((?!.).) で囲うようにしているのは、たとえば仮に文字列のリストが空の場合、何にもマッチしない正規表現を作るためにしています。 この場合、空のリストを入力すると ((?!.).) となりこれは何にもマッチしません。ただ単に () を生成してしまうとどこにでもマッチする表現になってしまいます。 だいたいの、こういう単語などの文字列リストをマッチさせるという用途の場合、空のリストの場合は何にもマッチしない動作が望ましいと考えています。
    • (?!.).は何にもマッチしない正規表現として使用していますが、同じことができるなら他の表現でも問題ありません。 何にもマッチしない正規表現は過去のエントリにも書きました http://knjname.hateblo.jp/entry/2014/03/19/024810 が、過去のエントリの $^ だと、空の文字列にマッチしてしまうようです。($^にとって、空の文字列の開始位置は行末とも言えるし、行頭とも言えるのでマッチできる。$^. とかなら問題ないかも。 )
  • Pattern.quote(文字列) というのは正規表現のメタ文字などを無害な文字列にするメソッドで、今回のリストの文字列要素では必要にはなりませんが、一般的な文字列のリストを処理する場合必要です。 https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#quote-java.lang.String-