一部 pcregrep
1 を用いて説明しているが、これは言語仕様によるノイズを排除するためのもの
# STRING => 検索文字列
# REGEXP => 正規表現
% echo STRING | pcregrep 'REGEXP'
の形で説明に利用している。
先に結論
16 進数表記を用いて記載する。特にお勧めは、\xhh
形式(ブレース無し)の \x5c
。2
% echo \\ | pcregrep '\x5c'
\ # <= マッチしている
こちらで記載するクセを付けると正規表現中に埋没することなく、
「ああ、バックスラッシュも対象なんだな。」と一目で判断が付く。
# `[` か `\` か `]` に当るカスタム文字クラス
% echo \\ | pcregrep '[\[\x5c\]]'
\ # <= マッチしている
言語依存で、\x5c
のバックスラッシュにエスケープが必要だとしても、
エスケープシーケンスは、\
、文字列は \x5c
と切り分ければ、可読性が確保出来る。
# `[` か `\` か `]` に当るカスタム文字クラス
% python -c 'import re; print(bool(re.match("[\[\\\\\]]", "\\")))'
True
# => r"" を使わないと、\x5c の \ にエスケープが必要となる
% python -c 'import re; print(bool(re.match("[\[\\x5c\]]", "\\")))'
True
上記の通り、わかりやすい。
あとは、コメントに「\x5c
は、 \
の 16 進数表記です。」と一言書いておけば、初見の人でも理解出来るはず。
一部言語では、宣言時に \x5c
を展開してしまうため、エスケープや展開抑制の処理をする必要があるが、致し方ない。
以上、本稿の主張は終り。 気が向いたら下の文章も読んで下さい。
バックスラッシュを重ねることの問題点、というか発端
- 言語依存で、一文字エスケープするのに
\\\\
と書かなければいけないものとかある
ついでに言えば、\\\
と書ける場合があったりする - その言語を学習すれば、
\\
と書ける様に出来る。すなわち、言語依存のため学習コストがかかる3 が、往々にして、その学習を怠るものだ - (本稿では言及しないが)そう言うコードは、メタ文字以外も無意味にエスケープしまくっている
- そして、そのコードを渡されて、途方にくれる、、、
結論の所に例を書いたが、バックスラッシュのエスケープの数をちょっと変更すると、
# ここでは Python での例
# ◯ エスケープ 7個 + \ 自身
# [ か \ か ] に当たる
# => 文字クラス内に \ 自身が2回含まれる形
% python -c 'import re; print(bool(re.match("[\[\\\\\\\\\]]", "\\")))'
# ◯ エスケープ 4個 + \ 自身
# [ か \ か ] に当たる
# => 余った \ は? ケースバイケースで無視されるのか?
% python -c 'import re; print(bool(re.match("[\[\\\\\\]]", "\\")))'
True
# ◯ エスケープ 2個 + \ 自身
# [] か、\] に当たる(カスタム文字クラスの定義は "[\[\\\\]" の部分)
# => 想定と違い、エスケープ 3個 + \ 自身として処理される
% python -c 'import re; print(bool(re.match("[\[\\\\]]", "\\")))'
False
# ◯ エスケープ 1個 + \ 自身
# [] か、\] に当たる(カスタム文字クラスの定義は [\[\\\] の部分)
# => 想定と違い、エスケープ 2個 + \ 自身として処理される
% python -c 'import re; print(bool(re.match("[\[\\\]]", "\\")))'
False
# ◯ エスケープ 1個
# [ か、] に当たる
# => 余った \ は? ケースバイケースで無視されるのか?
% python -c 'import re; print(bool(re.match("[\[\\]]", "\\")))'
False
こう言う風に動作してしまう。
問題は、意図的に書いたのか、間違えたのか判断出来ない場合がある4 し、言語間でも
挙動が変る場合があると言うことだ。
16進数表記を用いる
より、言語間で挙動の違いが少なくする為に。
既に結論で書いてはいるが、再度。
正規表現には Ascii コードを埋め込み検索する事が可能。
\
の 16 進数 Ascii コードは 5c
、そして多くのスクリプト言語の実装では、\xhh
の表記がサポートされている。
つまり、正規表現中に \x5c
と書く
# `[` か `\` か `]` に当るカスタム文字クラス
% python -c 'import re; print(bool(re.match(r"[\[\x5c\]]", "\\")))'
True
% python -c 'import re; print(bool(re.match("[\[\\x5c\]]", "\\")))'
True
\\\\
よりは、\x5c
の方が一塊と判断しやすく可読性に優れている。
PHP における \x5c
と \x{5c}
PHP では別の記法として \x{hh}
が用意されている。で、これの挙動が一致しない。
% php -r 'print(preg_match("/\x5c/", "\\")) . "\n";'
PHP Warning: preg_match(): No ending delimiter '/' found in Command line code on line 1
Warning: preg_match(): No ending delimiter '/' found in Command line code on line 1
% php -r 'print(preg_match("/\x{5c}/", "\\")) . "\n";'
1
どちらかの挙動に合せようとしなかったのだろうか。
これが同様に \x{hh}
がサポートされている Perl だと一致している。
% perl -le 'print "\\" =~ /\x5c/;'
1
% perl -le 'print "\\" =~ /\x{5c}/;'
1