0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHP, Python の正規表現で、何故 \\ でバックスラッシュ \ がエスケープ出来るケースがあるのか

Last updated at Posted at 2024-07-06

バックスラッシュ自身 \ に対する正規表現で、バックスラッシュ 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 が渡る様にしたい訳で。
その場合、以下のパターンが考えられる。

  1. \\ のそれぞれの展開を抑制させるために、それぞれエスケープする(~\~\)
  2. \x5c の展開を抑制するために先頭の \ をエスケープする(~\x5c)
  3. 文字列 \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

うん、沼りそうなので、ここで止め。

  1. 過去にあった同様の記事は見当らない、埋もれてる or 失われているので、、、

  2. PCRE の純正 grep。インストールの仕方などは省略 (PHP が入ってる環境なら入っているでしょ、知らんけど)

  3. 多くの言語は、このレベルでのみのエスケープで済む

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?