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