OK,讓我們嘗試重新mb_convert_case
儘可能接近但只改變每個單詞的第一個字符
的mb_convert_case
執行相關部分是這樣的:
int mode = 0;
for (i = 0; i < unicode_len; i+=4) {
int res = php_unicode_is_prop(
BE_ARY_TO_UINT32(&unicode_ptr[i]),
UC_MN|UC_ME|UC_CF|UC_LM|UC_SK|UC_LU|UC_LL|UC_LT|UC_PO|UC_OS, 0);
if (mode) {
if (res) {
UINT32_TO_BE_ARY(&unicode_ptr[i],
php_unicode_tolower(BE_ARY_TO_UINT32(&unicode_ptr[i]),
_src_encoding TSRMLS_CC));
} else {
mode = 0;
}
} else {
if (res) {
mode = 1;
UINT32_TO_BE_ARY(&unicode_ptr[i],
php_unicode_totitle(BE_ARY_TO_UINT32(&unicode_ptr[i]),
_src_encoding TSRMLS_CC));
}
}
}
基本上,這將執行以下操作:
- 設置
mode
到0
。 mode
將決定我們是否在單詞的第一個字符。如果是0
,我們是,否則我們不是。
- 遍歷字符串的字符。
- 確定它是什麼樣的字符。
- 將
res
設置爲1
如果它是單詞字符。更具體地說,如果它具有「標記,非間距」,「標記,圍合」,「其他,格式」,「字母,修飾符」,「符號,修飾符」,「字母,大寫」等屬性,則將其設置爲1
。 「Letter,Lowercase」,「Letter,Titlecase」,「標點符號,其他」或「其他代理人」。奇怪的是,「信,其他」不包括在內。
- 如果我們在一個字
- 如果我們在單詞字符的開始不是,將其轉換爲小寫 - 這是我們不希望。
- 否則,我們不是一個單詞字符,並且我們將
mode
設置爲0
以表示我們正在移動到單詞的開頭。
- 如果我們在單詞的beggining,我們確實有一個單詞字符
- 轉換這個角色大寫的標題
- 信號我們不再在一個單詞的開頭。
的mbstring擴展似乎並沒有露出字符屬性。這給我們留下了一個問題,因爲我們沒有一個好的方法來確定一個角色是否具有mb_convert_case
測試的10個屬性中的任何一個。
幸運的是,unicode character properties in regex可以拯救我們在這裏。
的mb_convert_case
與問題轉換爲小寫的忠實再現變爲:
function mb_convert_case_utf8_variation($s) {
$arr = preg_split("//u", $s, -1, PREG_SPLIT_NO_EMPTY);
$result = "";
$mode = false;
foreach ($arr as $char) {
$res = preg_match(
'/\\p{Mn}|\\p{Me}|\\p{Cf}|\\p{Lm}|\\p{Sk}|\\p{Lu}|\\p{Ll}|'.
'\\p{Lt}|\\p{Sk}|\\p{Cs}/u', $char) == 1;
if ($mode) {
if (!$res)
$mode = false;
}
elseif ($res) {
$mode = true;
$char = mb_convert_case($char, MB_CASE_TITLE, "UTF-8");
}
$result .= $char;
}
return $result;
}
測試:
echo mb_convert_case_utf8_variation("HETÁ1200 Ááxt ítring uii");
給出:
HETÁ1200 Ááxt Ítring Uii
謝謝。這很巧妙!也非常感謝你的解釋。 :) – Lyon 2010-07-31 13:41:16