17

\wPCRE (特に PHP の実装) では、システムのロケールに応じて一部の非 ASCII 文字と一致する場合があることは既に認識していますが、どう[a-z]ですか?

私はそうは思いませんが、Drupal のコア ファイル (includes/theme.inc、簡略化) の 1 つに次の行があることに気付きました。

// To avoid illegal characters in the class,
// we're removing everything disallowed. We are not using 'a-z' as that might leave
// in certain international characters (e.g. German umlauts).
$body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', $class);

これは本当ですか、それとも単に誰かが と[a-z]混同したの\wですか?

4

3 に答える 3

13

簡単に言えば、おそらく、アプリがデプロイされるシステムに依存し、PHP がどのようにコンパイルされたかに依存します。ローカリゼーションと国際化の CF へようこそ。

基盤となる PCRE エンジンは、"az" の意味を判断する際にロケールを考慮します。スペイン語ベースのロケールでは、ñ は az によってキャッチされます)。az の意味的な意味は、「a と z の間のすべての文字であり、ñ はスペイン語の別の文字です。

ただし、PHP がやみくもに文字列を UTF コード ポイントのコレクションとしてではなく、バイトのコレクションとして処理する方法は、az がアクセント付き文字に一致する可能性があることを意味します。Drupal が展開されるさまざまなシステムを考えると、az が正しいことを行うと単に信頼するのではなく、許可された文字について明示することを選択することは理にかなっています。

また、この正規表現の存在は、ドイツ語のウムラウトがフィルタリングされていないというバグ レポートが提出された結果であると推測します。

2014 年の更新:以下の JimmiTh の回答によると、(「pcre-core 以外の開発者にとって紛らわしい」ドキュメントがあるにもかかわらず) 99% の確率[a-z]で文字のみに一致するように見えます。abcdefghijklmnopqrstuvwxyzとはいえ — フレームワーク開発者は、コードのあいまいさについて神経質になる傾向があります。特に、コードがシステム (ロケール固有の文字列) に依存していて、PHP が適切に処理できない場合や、開発者が制御できないサーバーを使用している場合はそうです。匿名の Drupal 開発者のコ​​メントは正しくありませんが、それは「[a-z]混乱する\w」という問題ではなく、Drupal 開発者が PCRE の処理方法を不明確/不確かにしているためです[a-z]abcdefghijklmnopqrstuvwxyz

于 2009-12-18T21:02:15.187 に答える
10

Drupal のコードのコメントWRONGです。

" " が一致する可能性があるというのは正しくありませんinternational characters (e.g. German umlauts)[a-z]

たとえば、ドイツ語のロケールが利用可能な場合は、次のように確認できます。

setlocale(LC_ALL, 'de_DE'); // German locale (not needed, but you never know...)
echo preg_match('/^[a-z]+$/', 'abc') ? "yes\n" : "no\n";
echo preg_match('/^[a-z]+$/', "\xE4bc") ? "yes\n" : "no\n"; // äbc in ISO-8859-1
echo preg_match('/^[a-z]+$/',  "\xC3\xA4bc") ? "yes\n" : "no\n"; // äbc in UTF-8
echo preg_match('/^[a-z]+$/u', "\xC3\xA4bc") ? "yes\n" : "no\n"; // w/ PCRE_UTF8

de_DE出力 ( に置き換えても変化しませんde_DE.UTF-8):

yes
no
no
no

文字クラスは、PCRE が理解する両方のエンコーディング (ASCII 派生モノバイトおよび UTF-8 (これも ASCII 派生))[abcdefghijklmnopqrstuvwxyz]と同一です。[a-z]これらのエンコーディングの両方で、[a-z]は と同じ[\x61-\x7A]です。

2009年に質問されたときは状況が異なっていた可能性がありますが、2014年には、PHPのPCRE正規表現エンジン[a-z]が26文字を超えるクラスとして解釈できる「奇妙な構成」はありません([a-z]それ自体が5バイトとして書かれている限り)もちろん、ASCII から派生したエンコーディング)。

于 2014-04-01T07:37:48.003 に答える
7

矛盾している場合でも、すでに優れた両方の回答に追加するだけです。

PCRE ライブラリのドキュメントには、「範囲は文字値の照合シーケンスで動作する」と常に記載されています。これはやや曖昧ですが、非常に正確です。

を使用して現在のロケールに一致するように設定できる、PCRE の内部文字テーブル内の文字のインデックスによる照合を指しますpcre_maketables。その関数は、char 値 ( tolower(i)/ toupper(i))の順にテーブルを構築します。

つまり、実際の文化的な並べ替え順序 (ロケール照合情報) では照合されません。例として、ドイツ語は ö を辞書照合で o と同じように扱いますが、ö は、ドイツ語で使用されるすべての一般的な文字エンコーディング (ISO-8859-x、Unicode エンコーディングなど) で az 範囲外に表示される値を持ちます。この場合、PCRE は、[a-z]実際のロケール定義の並べ替え順序ではなく、ö がそのコード値の範囲内にあるかどうかを判断します。

PHP はほとんどの場合、 PCRE のドキュメントを docsに逐語的にコピーしています。ただし、実際には、上記のステートメントを「範囲はASCII照合シーケンスで動作する」に変更するのに苦労しました。この声明は、少なくとも 2004 年以降はドキュメントに含まれています。

上記にもかかわらず、それが本当かどうかはよくわかりません。

少なくとも、すべての場合ではありません。

PHPが行う1つの呼び出しpcre_maketables... PHPソースから:

#if HAVE_SETLOCALE
    if (strcmp(locale, "C"))
        tables = pcre_maketables();
#endif

つまり、PHP がコンパイルされる環境がsetlocale あり、(LC_CTYPE) ロケールが POSIX/C ロケールでない場合、実行環境の POSIX/C ロケールの文字順序が使用されます。それ以外の場合は、コンパイラのロケールに基づいて、pcre_maketables PCRE のコンパイル時に(によって) 生成されるデフォルトの PCRE テーブルが使用されます。

この関数は、256 未満の文字値の一連の文字テーブルを作成します。これらを pcre_compile() に渡して、PCRE の内部の組み込みテーブル (PCRE のコンパイル時に pcre_maketables() によって作成されたもの) をオーバーライドできます。非標準のロケールを使用している場合は、これを行うことができます。この関数は、テーブルへのポインターを生成します。

ドイツ語は[a-z]どの一般的な文字エンコーディングでも違いはありませんが、たとえば、EBCDIC を扱っている場合は[a-z]、± と ~ が含まれます。確かに、EBCDIC は、az と AZ を連続したシーケンスに配置しない、私が考えることができる唯一の文字エンコーディングです。

PCRE が EBCDIC を使用するときに何らかの魔法を行わない限り (そしてそうなる可能性があります)、最もあいまいな PHP ビルドまたはランタイム環境 (独自の非常に特別なカスタムメイドのロケール定義を使用する) 以外にウムラウトを含めることはほとんどありません。 、EBCDIC の場合は、他の意図しない文字を含めることができます。また、他の範囲については、「ASCII シーケンスで照合」は完全に正確ではないようです。

ETA:同様の懸念に対する Philip Hazel 自身の回答を探すことで、調査を節約できたかもしれません。

別の問題は、文字クラスの範囲にあります。[ak] と [xz] はラテン文字用に適切に定義されていると思われるかもしれませんが、そうではありません。

それらは確かに明確に定義されており、[\x61-\x6b] および [\x78-\x7a] と同等です。つまり、文化的な並べ替え順序ではなく、コードの順序に関連しています。

于 2014-04-06T10:35:51.790 に答える