2009-12-18 68 views
17

我已經知道PCRE中的\w(特別是PHP的實現)有時可以匹配一些非ASCII字符,具體取決於系統的區域設置,但[a-z][a-z]是否會在PREG/PCRE中匹配重音字符?

我不這麼認爲,但我注意到在Drupal的核心文件中的一個,這些線路(包括/ theme.inc,簡化):

// 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

回答

13

長話短說:也許,取決於應用程序部署到的系統,取決於如何編譯PHP,歡迎來到本地化和國際化的CF。

底層PCRE引擎在確定「a-z」的含義時考慮了區域設置。在西班牙語的語言環境中,ñ會被a-z抓住)。 AZ的語義是「所有A和Z之間的字母,N是西班牙一個單獨的字母。

然而,PHP一味地處理字符串作爲一個字節的集合,而不是UTF代碼點集合的方式意味着你有一種情況,az可能匹配重音字符考慮到Drupal部署的各種不同系統,它們會選擇明確允許的字符而不是僅僅信任az來做正確的事情。

我也猜想這個正則表達式的存在是由於德國變音器沒有被過濾而引起的錯誤報告的結果。

更新在2014年:每JimmiTh's answer below,它看起來像(儘管有些「混亂到非PCRE核心開發人員」文檔)是[a-z]將只匹配字符abcdefghijklmnopqrstuvwxyz時一個衆所周知的99% 。這就是說 - 框架開發人員傾向於在代碼中模糊不清,特別是當代碼依賴於系統(特定於語言環境的字符串)時,PHP無法按照您的意願優雅地處理,以及開發人員無法控制的服務器。儘管匿名的Drupal開發者的評論是不正確的 - 這不是「得到[a-z]\w混淆」的問題,而是一個Drupal開發者不清楚/不確定PCRE如何處理[a-z],並選擇更具體的abcdefghijklmnopqrstuvwxyz形式來確保他們想要的具體行爲。

+0

這是真的在2009年嗎? – 2014-04-02 06:18:38

+0

@WalterTross今天仍然如此,真是如此。它從來不是關於什麼是/是常見的,而是關於一些奇怪的配置會發生什麼,並確保您的代碼足夠健壯以處理它。 – 2014-04-02 07:36:37

+1

@AlanStorm,你能提供這麼奇怪的配置嗎?我很確定沒有! – 2014-04-02 08:30:03

10

The comment在Drupal的代碼是錯誤

這是不是確實「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.UTF-8替換de_DE不會改變):

yes 
no 
no 
no 

的字符類[abcdefghijklmnopqrstuvwxyz]等同於[a-z]在這兩種編碼中,PCRE都能理解:ASCII派生的monobyte和UTF-8(也是ASCII派生的)。在這兩種編碼中,[a-z][\x61-\x7A]相同。

情況可能有所不同,當有人問在2009年,但在2014年沒有「怪異配置」,可以使PHP的PCRE正則表達式引擎解釋[a-z]作爲一類超過26個字符(只要[a-z]本身當然是以ASCII碼派生的編碼寫成5個字節)。

+1

你釘了它+1 – HamZa 2014-04-03 21:49:20

+0

當PHP文件的編碼改變時會發生什麼? – 2014-04-10 23:16:27

+0

@AlanStorm:只要編碼是ISO-8859- *,UTF-8或包含英文小寫字母的任何Windows代碼頁:無。另一方面,它看起來像PHP可以編譯爲了讀取,例如,UTF-16源代碼(我不知道這一點)。我沒有精力去嘗試。如果有人有,他們可以在這裏發表他們的發現。 – 2014-04-11 12:29:20

7

除了已經很好的,如果矛盾的答案,只是一個補充。

PCRE庫的文檔一直聲明「範圍在字符值的整理順序中運行」。這有點模糊,但非常精確。

它指的是通過在PCRE內部字符表的字符的索引,其可被設置以匹配使用pcre_maketables當前區域整理。該函數按照char值的順序構建表(tolower(i)/toupper(i)

換句話說,它不按實際的文化排序順序(區域設置排序規則信息)進行排序。例如,雖然德語在詞典整理中將o與o相同,但ö的值使其在德語所使用的所有常用字符編碼(ISO-8859-x,unicode編碼等)中出現在z範圍外。在這種情況下,PCRE將根據該代碼值確定ö是否在[a-z]範圍內,而不是任何實際的區域設置排序順序。

PHP大多複製PCRE's documentation逐字在their docs。但是,他們實際上已經努力將上述語句更改爲「範圍在ASCII對齊序列中操作」。至少自2004年以來,這種說法一直在文檔中。

儘管如此,但我不太確定它是否屬實。嗯,至少在所有情況下都不是這樣。

的一個調用PHP使得以pcre_maketables ...從PHP source

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

換句話說,如果該PHP編譯環境有setlocale的(LC_CTYPE)語言環境未POSIX/C語言環境,運行時環境的POSIX/C語言環境的字符順序被使用。否則,默認PCRE表用於 - 其中產生(由pcre_maketables)時PCRE編譯 - 基於編譯器的語言環境

該函數建立了一組字符表的字符值小於256。可以將這些傳遞給pcre_compile()以覆蓋PCRE的內部內置表(當編譯PCRE時,由pcre_maketables()生成)。如果您使用的是非標準語言環境,則可能需要執行此操作。該函數產生一個指向表的指針。

而德國將不會在任何普通的字符編碼是[a-z]不同,如果我們處理EBCDIC,例如,[a-z]將包括±和〜。當然,EBCDIC是我能想到的一種字符編碼方式,它不會以不間斷的順序放置a-z和A-Z。

除非PCRE在使用EBCDIC(可能的話)時會有一些神奇的功能,儘管極其不可思議的是,除了最晦澀的PHP構建或運行時環境之外,您還會在其中包含變音器(使用您自己的,非常特殊的,您的可能,在EBCDIC的情況下,包括其他意想不到的字符。而對於其他範圍,「按ASCII順序整理」似乎並不完全準確。

ETA:我可以通過尋找菲利普·黑茲爾自己回答了類似的擔憂已經存了一些研究:

另一個問題是與字符類範圍。你會認爲[a-k]和[x-z]對於拉丁腳本是很好的定義,但事實並非如此。

他們肯定明確的,等同於[\ x61- \ X6B]和[\ x78- \ X7A],也就是涉及到代碼順序,而不是文化的排序順序。

+1

[pcre_maketables()](http://vcs.pcre.org/viewvc/code/trunk/pcre_maketables.c?view=markup)只生成以下表格:下方的表格,案例翻轉表,字符類表,字符類型表。它不涉及整理。關於EBCDIC,如果有人向我展示一臺實際運行PHP的EBCDIC機器,PHP中的PCRE將'[a-z]'解釋爲'[\ x81- \ xA9]',我就放棄了。 – 2014-04-06 22:33:27

+0

是的。因此「換句話說,它不會按照實際的文化排序順序(區域設置整理信息)進行整理」。答案*的全部要點是*它不處理排序規則。 – JimmiTh 2014-04-06 22:40:23

+1

strcmp(3)的瑣碎事情是,當字符串匹配時它返回false的等價物。所以,pcre_maketables被稱爲任何東西,但C語言環境。 – Melvyn 2014-04-09 06:42:05

相關問題