代码:
setlocale(LC_ALL, 'pl_PL', 'pl', 'Polish_Poland.28592');
$result = mb_stripos("ĘÓĄŚŁŻŹĆŃ",'ęóąśłżźćń');
返回false;
如何解决这个问题?
注:当使用特殊字符不是正确答案时,此stripos返回false。
更新:我做了一个测试:
function test() {
$search = "zawór"; $searchlen=strlen($search);
$opentag="<valve>"; $opentaglen=strlen($opentag);
$closetag="</valve>"; $closetaglen=strlen($closetag);
$test[0]['input']="test ZAWÓR test"; //normal test
$test[1]['input']="XnXnX ZAWÓR XnXnX"; //white char test
$test[2]['input']="<br> ZAWÓR <br>"; //html newline test
$test[3]['input']="ĄąĄą ZAWÓR ĄąĄą"; //polish diacritical test
$test[4]['input']="テスト ZAWÓR テスト"; //japanese katakana test
foreach ($test as $key => $val) {
$position = mb_stripos($val['input'],$search,0,'UTF-8');
if($position!=false) {
$output = $val['input'];
$output = substr_replace($output, $opentag, $position, 0);
$output = substr_replace($output, $closetag, $position+$opentaglen+$searchlen, 0);
$test[$key]['output'] = $output;
}
else {
$test[$key]['output'] = null;
}
}
return $test;
}
FIREFOX输出:$test[0]['output'] == "test <valve>ZAWÓR</valve> test" // ok
$test[1]['output'] == "XnXnX <valve>ZAWÓR</valve> XnXnX" // ok
$test[2]['output'] == "<br> <valve>ZAWÓR</valve> <br>" // ok
$test[3]['output'] == "Ąą�<valve>�ą ZA</valve>WÓR ĄąĄą" // WTF??
$test[4]['output'] == "テ�<valve>��ト </valve>ZAWÓR テスト" // WTF??
解决方案https://drupal.org/node/1107268不会改变任何东西
当被告知字符串的编码时,该函数可以正常工作:
var_dump(mb_stripos("ĘÓĄŚŁŻŹĆŃ",'ęóąśłżźćń', 0, 'UTF-8')); // 0
^^^^^^^
如果没有显式的encoding参数,它可能会假设错误的编码,从而无法正确处理您的字符串。
你的测试代码的问题是你混合了基于字符的索引和基于字节偏移的索引。mb_strpos
返回字符的偏移量,而substr_replace
使用字节偏移量。阅读这里的主题:每个程序员绝对需要知道的关于编码和字符集的文本工作。
如果您想在多字节字符串中包装标签中的某个单词,我更建议使用这种方法:
preg_replace('/zawór/iu', '<valve>$0</valve>', $text)
注意$text
必须为UTF-8编码,/u
正则表达式只支持UTF-8。
我不知道为什么mb_stripos
函数不工作,但解决方案将工作如下,
$str = mb_convert_case("ęóąśłżźćń", MB_CASE_UPPER, "UTF-8");
$result = mb_strrichr($str,"ĘÓĄŚŁŻŹĆŃ");
var_dump($result);
。
使用你的提示,亲爱的Rikesh,我写了:
function patched_mb_stripos($content,$search) {
$content=mb_convert_case($content, MB_CASE_LOWER, "UTF-8");
$search=mb_convert_case($search, MB_CASE_LOWER, "UTF-8");
return mb_stripos($content,$search);
}
,它似乎工作:)
解决方案https://gist.github.com/stemar/8287074:
function mb_substr_replace($string, $replacement, $start, $length=NULL) {
if (is_array($string)) {
$num = count($string);
// $replacement
$replacement = is_array($replacement) ? array_slice($replacement, 0, $num) : array_pad(array($replacement), $num, $replacement);
// $start
if (is_array($start)) {
$start = array_slice($start, 0, $num);
foreach ($start as $key => $value)
$start[$key] = is_int($value) ? $value : 0;
}
else {
$start = array_pad(array($start), $num, $start);
}
// $length
if (!isset($length)) {
$length = array_fill(0, $num, 0);
}
elseif (is_array($length)) {
$length = array_slice($length, 0, $num);
foreach ($length as $key => $value)
$length[$key] = isset($value) ? (is_int($value) ? $value : $num) : 0;
}
else {
$length = array_pad(array($length), $num, $length);
}
// Recursive call
return array_map(__FUNCTION__, $string, $replacement, $start, $length);
}
preg_match_all('/./us', (string)$string, $smatches);
preg_match_all('/./us', (string)$replacement, $rmatches);
if ($length === NULL) $length = mb_strlen($string);
array_splice($smatches[0], $start, $length, $rmatches[0]);
return join("",$smatches[0]);
}
用函数test()解决了这个问题