そういうわけでメモ。
Groovyの場合、肯定的先読みは(?=pattern)、肯定的後読みは(?<=pattern)と書く。
※patternの部分は判別させたい文字列。
先読み、後読みは何に使うのかというと、「文字列の前と後にどんな文字が来るか判別したくて、なおかつその部分にはマッチさせたくない」という場合に使う。
たとえば、「hoge(?=pattern)」は patternが後ろにあるhogeにマッチするが、(?=pattern)部分にはマッチしない。
「(?<=pattern)hoge」は patternが前にあるhogeにマッチするが、(?=<pattern)部分にはマッチしない。
マッチしたい文字の前に後読み、後ろに先読みを使うのがミソ。
順番でいうと(後読み)(欲しい部分)(先読み)と使う。
ここまでOK?
実例。下のような文章があったとする。
長嶋 茂雄の誕生日は1936年2月20日。
1974(昭和11)年2月20日から
2008(平成20)年11月20日の間の日数は26,572日、
72年と274日になります。ところで、ただいまの時間は7:19です。
「ところで」の部分が苦しい…のは置いといて、
このテキストの「1桁と2桁の数字だけ<tcy></tcy>というタグで囲みたい」。
どうしよう?
まず、1桁と2桁の数字だから、
\d{1,2}
だけど、これだと3桁以上の数字にもマッチしてしまうので、前後に数字がない場合だけマッチさせたい。
(?<=[^\d])(\d{1,2})(?=[^\d])
また、コンマ区切りと小数点、時間を表しているコロンがあった場合もマッチさせたくない。
(?<=[^\d\.,:])(\d{1,2})(?=[^\d\.,:])
この文章にはないけれど、行頭もしくは行末に数字が来るかもしれない。
(?<=^|[^\d\.,:])(\d{1,2})(?=[^\d\.,:]|$)
これで、数字2桁までの「数字部分にだけ」マッチする。
以下Groovyスクリプト。
def text="""長嶋 茂雄の誕生日は1936年2月20日。
1974(昭和11)年2月20日から
2008(平成20)年11月20日の間の日数は26,572日、
72年と274日になります。ところで、ただいまの時間は7:19です。"""
//半角1,2桁の数字にタテ中ヨコ用タグ付け
text=text.replaceAll(/(?<=^|[^\d\.,:])(\d{1,2})(?=[^\d\.,:]|$)/) {
m0, m1 -> "<tcy>${m1}</tcy>"
}
println(text)

ところで、JavaScriptも正規表現を使えるけれど、後読みをサポートしていない。
仕方がないので、後読み部分を普通にマッチさせる。後読み部分も1字なので不具合は出ないと思う。
以下ExtendScript。
var text="長嶋 茂雄の誕生日は1936年2月20日。\n"
+"1974(昭和11)年2月20日から\n"
+"2008(平成20)年11月20日の間の日数は26,572日、\n"
+"72年と274日になります。ところで、ただいまの時間は7:19です。"
//半角1,2桁の数字にタテ中ヨコ用タグ付け
text=text.replace(/(^|[^\d\.,:])(\d{1,2})(?=[^\d\.,:]|$)/g,"$1"+"<tcy>"+"$2"+"</tcy>");
$.writeln(text);

2 コメント:
先読み、後読み。
これは強力ですね。
勉強になりました。
ゲンゾウさん、はじめまして
リンクありがとうございますm(_ _)m
時々読ませていただいてます。
自分もこれまで正規表現って謎だらけだったんですが、これで少しは使えそうな気がしています。
コメントを投稿