home wiki.fukuchiharuki.me
Menu

はじめに

Javaも正規表現をサポートしていて Perlと同等の処理をすることができる(らしい。) ここでは、正規表現を使ってパターンマッチする部分文字列について 条件を当てながら置換する方法について記載する。

想定するケース

「テキスト中のリンクのうち、 外部サイトを参照するものを別ウィンドウに表示する」 ケースを考える。 つまり 「テキスト中のアンカタグのうち、 参照URLがある条件を満たす場合のみ target="_blank" を挿入する」 と言い換えることができる。

要件を抜き出すと、

  • テキスト中からアンカタグを抜き出す
  • 抜き出した文字列のうち参照URL部分について条件を当てる
  • 条件を満たした場合抜き出したアンカタグに target="\blank" を挿入する

となる。

実装

String regex = "(<a .*?href=[\"'])(.*?)([\"'])(.*?>)"; // アンカタグを抜き出す正規表現
StringBuffer tunedText = new StringBuffer(); // 置き換え後のテキスト
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text); // textは置き換え前のテキスト
while (matcher.find()) {
  if (! matcher.group(2).matches("^(http|https|ftp)://([^\\./]+\\.)*foo\\.bar(/.*)?$")) {
    matcher.appendReplacement(tunedText, 
                              matcher.group(1)      // 「<a href="(アンカタグの先頭)」
                            + matcher.group(2)      // 「(URL)」
                            + matcher.group(3)      // 「"(hrefの閉じ)」
                            + " target=\"_blank\" " // 「target="_blank"(固定)」
                            + matcher.group(4));    // 「>(アンカタグの末尾)」
  }
}
matcher.appendTail(tunedText);

テキスト中からアンカタグを抜き出す

アンカタグを抜き出す正規表現を

(<a .*?href=[\"'])(.*?)([\"'])(.*?>)

としている。

ここでは抜き出すアンカタグを次の要素に分割している。

  • 「<a href="(アンカタグの先頭)」
  • 「(URL)」
  • 「"(hrefの閉じ)」
  • 「>(アンカタグの末尾)」

抜き出した文字列のうち参照URL部分について条件を当てる

分割した要素「(URL)」について条件を当てる。ここでは、

if (! matcher.group(2).matches("^(http|https|ftp)://([^\\./]+\\.)*foo\\.bar(/.*)?$"))

としている(条件は「foo.bar」をドメイン名とするURL以外の場合。)

条件を満たした場合抜き出したアンカタグに target="\blank" を挿入する

分割した要素「"(hrefの閉じ)」と「>(アンカタグの末尾)」の間に 「target="_blank"(固定)」を挿入して appendReplacement() している。

ここで appendReplacement() はカーソルの先頭からマッチした文字列の末尾までをアペンドし、 カーソルをマッチした文字列の末尾の次の文字に変更する。 従って、appendReplacement() を繰り返すことで マッチした文字列の末尾までを次々にアペンドできる。 最後に appendTail() をコールすることで、 最後にマッチした文字列の次の文字から後ろをアペンドする。