4. URLの/を補完
次はURLの/を補完する正規表現についてです。
URLの最後の/を補完する。 (最後に/があればそのままで、最後に/がなければ追加する)
対象データと期待する置換結果は、下記となります。
この問題のポイントは、最後に/があるのか、それともないかをどう判断するかです。答えは、下記となります。
(?<!/)$ を / に置換
否定戻り読みは、指定したパターンの直後でない位置にマッチします。たとえば、(?<!xy)
はxyの直後でない位置にマッチしますので、検索対象が
xyz
であれば、行頭と文字xの間、文字xと文字yの間、文字zと行末の間、の3箇所の位置にマッチします。
答えについて解説すると、まず、否定戻り読み(?<!/)
によって、前に文字/が存在しない位置にマッチします。続いて、行末を意味する$
を指定しているため、(?<!/)$
は、前に文字/が存在しない、かつ、次に行末がある位置にマッチするということです。この位置を/に置換することで、行末の/を補完しています。
行末を意味する$
は、肯定先読みの1種で、次に行末がある位置にマッチする。行頭を意味する^
は、肯定戻り読みの1種で、前に行頭がある位置にマッチする。と考えると、分かりやすいでしょう。
正規表現のイメージは、下記となります。
5. 指定文字の指定番目までの文字列を検索
次は、指定文字の指定番目までの文字列を検索する正規表現についてです。
行ごとに、3番目のXまでの文字列を検索する。
対象データと期待する検索結果は、下記となります(黄緑色が検索にヒットした部分です)。
この問題のポイントは、3番目のXという条件です。例えば、1番目のXまでなら^[^X]*X
で検索できます。否定文字クラスで、Xでない文字を表現し、量指定子で、Xでない文字が0回以上という指定をしています。そして、Xでない文字の0回以上の繰り返しにマッチした後で、Xにマッチさせています。
ちなみに、[^X]
とX
の両方にマッチする文字は存在しないので、バックトラックを考える必要のない*
となります。なぜ、両方にマッチする文字が存在しないかと言うと、[^X]
とX
は、補集合の関係にあるからです。
上記の正規表現をふまえて、3番目のXまでということで、^[^X]*X[^X]*X[^X]*X
を使うのも、一つの解ですが、下記のように括弧と量指定子を組み合わせてもいいでしょう。
^[^X]*X[^X]*X[^X]*X 別解 ^([^X]*X){3}
解説すると、まず行頭にマッチします。次に、(Xでない文字の0回以上の繰り返しにマッチした後で、Xにマッチする)のを3回繰り返します。最初は、下記のように考えると分かりやすいかもしれません。
まず行頭にマッチします。 次に、Xでない文字に0回以上マッチし、Xにマッチします。 次に、Xでない文字に0回以上マッチし、Xにマッチします。 次に、Xでない文字に0回以上マッチし、Xにマッチします。
また、
^[^X]*X ^[^X]*X[^X]*X ^[^X]*X[^X]*X[^X]*X
を順番に試してみると理解しやすいかもしれません。正規表現のイメージは、下記となります。
最後に
今回は、筆者が運営するサイト『正規表現パズル』の、基本編の正規表現を扱いました。実際にEmEditorで試すと学習効率が高いでしょう。
次回の正規表現の問題集は、応用編となります。
参考資料
- 『詳説 正規表現 第3版』 Jeffrey E.F. Friedl 著、長尾高弘 訳、オライリー・ジャパン、2008年4月
正規表現を作成する際の考え方が詳細に書かれている本です。本稿で使用している正規表現の用語は、この本と同じ用語を使ってます。
- 正規表現パズル 『指定文字列を含む行を検索』
本稿の「指定文字列を含む行を検索」で扱った正規表現を置いてます。
- 正規表現パズル 『指定文字列を含まない行を検索』
本稿の「指定文字列を含まない行を検索」で扱った正規表現と別解を置いてます。
- 正規表現パズル 『整数をカンマ区切りに置換』
本稿の「整数をカンマ区切りに置換」で扱った正規表現と別解を置いてます。
- 正規表現パズル 『URLの/を補完』
本稿の「URLの/を補完」で扱った正規表現と別解を置いてます。
- 正規表現パズル 『指定文字の指定番目までの文字列を検索』
本稿の「指定文字の指定番目までの文字列を検索」で扱った正規表現と別解を置いてます。