バックスラッシュ自身 \
に対する正規表現で、バックスラッシュ 2個(\\
) - 結果として埋め込まれるのは \\\
- で OK なケースがある。この説明を実際の仕様ではなく、日曜プログラマが理解可能なレベルで記載したい。1
当然 '//'
(PHP)、r""
(Python) は使わない前提での文章となる。
前知識
- PHP, Python では、正規表現エンジンレベルでのエスケープ(PHP では PCRE)の他に、言語側の文字列としての展開を抑制するエスケープの2段階が必要
- 16進表記の文字列(
\x5c
) は(正規表現エンジンレベルでは)、エスケープの必要が無い(当たり前)
一部 pcregrep
2 を用いて説明しているが、これは言語仕様によるノイズを排除するためのもの。
# STRING => 検索文字列
# REGEXP => 正規表現
% echo STRING | pcregrep 'REGEXP'
解
正規表現エンジンレベル側
正規表現エンジンレベルで文字列 \
にマッチさせるためには、エスケープ \
が必要。3
# PHP の正規表現エンジンである PCRE による実行
# ※ カスタム文字クラス内外
% echo '\\' | pcregrep '\\'
\
% echo '\\' | pcregrep '[\\]'
\
ところで \\
はエスケープ無しの \x5c
(Ascii 16進数)と記載可能である。
% echo '\\' | pcregrep '\x5c'
\
% echo '\\' | pcregrep '[\x5c]'
\
言語側
便宜上、言語側レベルでのエスケープシーケンスを ~
で表記する
言語側からは、正規表現エンジンに正しく \\
、もしくは、\x5c
が渡る様にしたい訳で。
その場合、以下のパターンが考えられる。
-
\\
のそれぞれの展開を抑制させるために、それぞれエスケープする(~\~\
) -
\x5c
の展開を抑制するために先頭の\
をエスケープする(~\x5c
) - 文字列
\x5c
の展開を抑制するために先頭の\
を 16進数表記のバックスラッシュでエスケープする(\x5c\x5c
)
まあ、こんな感じ。
で、\x5c
を \\
に変換し、~
を本来の \
で記載すると、\\\
か \\\\
となる。
簡単だが、証明終り。
後は、言語仕様が、これを許容するかどうか。(後述)
Appendix
実際の所の \\
+ \
PHP の場合は、文字クラス内外双方で通る。
% cat test.php
<?php
print(preg_match("/\\\\/", '\\')) . "\n";
print(preg_match("/\\\/", '\\')) . "\n";
print(preg_match("/[\\\\]/", '\\')) . "\n";
print(preg_match("/[\\\]/", '\\')) . "\n";
% php test.php
1
1
1
1
Python の場合、文字クラス外では通さない。
% cat test.py
import re;
print(bool(re.match('\\\\', "\\")))
#print(bool(re.match('\\\', "\\"))) # <= エラーで実行出来ず
print(bool(re.match('[\\\\]', "\\")))
print(bool(re.match('[\\\]', "\\")))
% python test.py
True
True
True
\x5c
で \
をエスケープ
PHP の場合は、文字クラス内外双方で通る。
% cat test.php
<?php
print(preg_match("/\x5c\/", '\\')) . "\n";
print(preg_match("/[\x5c\]/", '\\')) . "\n";
% php test.php
1
1
Python の場合、文字クラス外での \x5c\
は通さない。
% cat test.py
import re;
#print(bool(re.match('\x5c\', "\\"))) # <= エラーで実行出来ず
print(bool(re.match('[\x5c\]', "\\")))
% python test.py
True
うん、沼りそうなので、ここで止め。