やりたいこと
例えばHTMLコーディングしていて思いつきでつけたクラス名hoge1,hoge2,hoge3があったとして、そのクラス名を下記のように変更したい場合
置換前 -> 置換後 |
---|
hoge1 -> hoge2 |
hoge2 -> hoge3 |
hoge3 -> hoge4 |
※ひどい命名を変更するのではなく番号をずらします
普通に置換しようと思うと一旦hoge1を別の文字列に置換してその後hoge3に置換し直すというような2段階の工程が必要。1ページ分くらいならそれでも良いのですが、量が多いと意外と面倒なのでなんとか一発で置換できないかと試行錯誤した結果、perlのワンライナーで実現することに。
そもそもなぜperlを使うに至ったか
今回の肝は計算が必要になるという点です。
テキストエディタの置換機能もsedも対応していない...さらに調べたところ、perlは数値計算を含む置換に対応しているようだったので、これをワンライナーで実行すればいけるのでは...早速やってみました。
最終的なワンライナー
cat target.html | perl -pe 's/(?<=class\=(?:\x22|\x27)hoge)([1-3])(?=(?:\x22|\x27))/$1+1/eg' > replaced.html
Perlの部分解説
perl -pe 's/(?<=class\=(?:\x22|\x27)hoge)([1-3])(?=(?:\x22|\x27))/$1+1/eg'
オプション
perl -pe 's/(?<=class\=(?:\x22|\x27)hoge)([1-3])(?=(?:\x22|\x27))/$1+1/eg'
- -e
-e
の後ろに実行したいスクリプトを記載することでワンライナーでのprelスクリプトとして認識される。 - -p
入力データの各行を再帰的に処理。
スクリプトの内容
perl -pe 's/ (?<=class\=(?:\x22|\x27)hoge)([1-3])(?=(?:\x22|\x27)) / $1+1 /eg'
- s/正規表現パターン/置換後文字列/
perlの正規表現による基本的な文字列置換の構文。 - /g
1行内に複数マッチするパターンがあった場合、全てに対して置換処理を行う。 - /e
評価可能な計算式、変数を展開。※eをつけた回数分評価を行うというオプションなので、例えば/ee
という使い方も可能。
正規表現
perl -pe 's/(?<=class\=(?:\x22|\x27)hoge)([1-3])(?=(?:\x22|\x27))/$1+1/eg'
- ?<=
肯定後読み。今回の場合は直前にclass="
(またはclass='
)を含む場合true(class="
自体はマッチ文字列に含まない) - ?=
肯定先読み。今回の場合は直後に"
(または'
)を含む場合true("
自体はマッチ文字列に含まない)
- ?:
()の中をキャプチャしない。"
,'
はキャプチャしたい文字列ではないので除きます。 - \x22 \x27
\x
の後ろにASCIIコードの16進数表記下二桁を記載すると、ASCIIコードで文字列検索が出来ます。\x22
は"
、\x27
は'
を表します。(ワンライナーで実行する都合上ASCIIコード表記を使用します)
このように肯定後読みと肯定先読みを使用して、数値部分のみマッチするような正規表現を組みます。
補足
普通に/class="hoge([1-3])"/class="hoge$1+1"/
とやりたいところですが、/eオプションは/class="hoge$1+1"/
全体を数式と捉えるため、文字列が含まれているとエラーになります。そのため、数値のみをマッチさせるように、先読み・後読みを使用しました。
まとめ
perlのワンライナーを使えば数値計算出来ると分かった後、正規表現で数値だけ抜き出すというところが地味に第二関門でした。正規表現だけで本が1冊書けるのも納得です。ぜひとも親友になりたいです。