Мой вопрос, учитывая, что у меня есть следующий PHP-код для сравнения двух строк:
$cadena1='JUAN LÓPEZ YÁÑEZ';
$cadena2='JUAN LOPEZ YÁÑEZ';
if($cadena1===$cadena2){
echo '<p style="color: green;">The strings match!</p>';
}else{
echo '<p style="color: red;">The strings do not match. Accent sensitive?</p>';
}
Я замечаю, например, что если я сравниваю ЛОПЕЗ а также LÓPEZ тогда сравнение становится ложным.
Есть ли способ или функция для сравнения этих строк независимо от испанских акцентов?
Я бы заменил все акценты в ваших строках, прежде чем сравнивать их. Вы можете сделать это, используя следующий код:
$replacements = array('Ó'=>'O', 'Á'=>'A', 'Ñ' => 'N'); //Add the remaining Spanish accents.
$output = strtr("JUAN LÓPEZ YÁÑEZ",$replacements);
output
теперь будет равен cadena2
,
Две строки сравниваются с ложными, потому что они на самом деле отличаются последовательностью байтов. Чтобы сравнить их, нужно их нормализовать любым способом.
Лучший способ сделать это — использовать класс Transliterator, часть intl
расширение на PHP 5.4+.
Тестовый код:
<?php
$transliterator = Transliterator::createFromRules(':: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
$test = ['abcd', 'èe', '€', 'àòùìéëü', 'àòùìéëü', 'tiësto'];
foreach($test as $e) {
$normalized = $transliterator->transliterate($e);
echo $e. ' --> '.$normalized."\n";
}
?>
Результат:
abcd --> abcd
èe --> ee
€ --> €
àòùìéëü --> aouieeu
àòùìéëü --> aouieeu
tiësto --> tiesto
(взято из моего ответа здесь: mySQL — сопоставление латинской (английской) формы ввода с данными utf8 (не английскими) )
Это заменяет символы в соответствии с таблицами библиотеки ICU, которые чрезвычайно полны и хорошо протестированы. Перед транслитерацией это нормализует строку, поэтому она соответствует любому возможному способу представления символов, таких как — (например, может быть представлен 1 многобайтовым символом или как комбинация двух символов ˜ и n).
В отличие от использования soundex (), который также очень ресурсоемкий, он не сравнивает звуки, поэтому он более точный.
Почему бы просто не использовать сопоставления из расширения intl, класса Collator?
(и так далее — см. подробности в документации ICU или PHP)
$cadena1 = 'JUAN LÓPEZ YÁÑEZ';
$cadena2 = 'JUAN LOPEZ YÁÑEZ';
$coll = new Collator('es_ES');
$coll->setStrength(Collator::PRIMARY);
//$coll->setAttribute(Collator::CASE_LEVEL, Collator::ON);
var_dump($coll->compare($cadena1, $cadena2)); // 0 = equals
(конечно, строки должны быть в кодировке UTF-8)
Вы можете попробовать soundex()
функция, которая работает по крайней мере для вашего примера:
var_dump(soundex('LOPEZ'));
// string(4) "L120"
var_dump(soundex('LÓPEZ'));
// string(4) "L120"
Вы должны проверить это для разных слов, и если результаты не достаточно хороши, вы можете попробовать similar_text()
.
Увидеть пример с вашим кодом.
Попробуйте эту функцию из http://sourcecookbook.com/en/recipes/8/function-to-slugify-strings-in-php. Он заменит не-ASCII-символы на ASCII-символы в строке.
$cadena1='JUAN LÓPEZ YÁÑEZ';
$cadena2='JUAN LOPEZ YÁÑEZ';
function slugify( $text ) {
// replace non letter or digits by -
$text = preg_replace('~[^\\pL\d]+~u', '-', $text);
$text = trim($text, '-');
/**
* //IGNORE//TRANSLIT to avoid errors on non translatable characters and still translate other characters
* //TRANSLIT to out_charset transliteration is activated
* //IGNORE, characters that cannot be represented in the target charset are silently discarded
*/
$text = iconv('utf-8', 'ASCII//IGNORE//TRANSLIT', $text);
$text = strtolower(trim($text));
// remove unwanted characters
$text = preg_replace('~[^-\w]+~', '', $text);
return empty($text) ? '' : $text;
}
var_dump( slugify( $cadena1 ) ); // string(16) "juan-lopez-yanez"var_dump( slugify( $cadena2 ) ); // string(16) "juan-lopez-yanez"