В очередной раз написав "поиск" для проекта задумался о его удобстве. Очень малое число людей владеет слепым методом печати, поэтому вводят не глядя на экран. В результате появляются такие вещи типа «Bpvtytybt hfcrkflrb cnhjrb d ЗРЗ bkb Згтещ Ыцшесрук yf зрз» (Изменение раскладки строки в PHP или Punto Switcher на php). Заставлять юзера вводить текст заново, как-то не гуманно. Яша и Гугл автоматически подбирают верный вариант. Чем мы хуже.
Чтобы поиск был более-менее адекватный, надо переводить раскладку во все возможные варианты написания, к примеру: «hfcrkflrf ЗРЗ» нужно перевести в «раскладка ЗРЗ» и «раскладка PHP» и проверить все три варианта. По хорошему надо делать 3 разных запроса и выводить данные по тому, который вернул больше всего данных, либо выводить все варианты, но тот что находит больше всего выводить выше.
Поиск в гугле по запросу зрз раскладка, выдал мне эту статейку. В ней дается такая функция
<?php function textswitch ($text) { $str_search = array( "й","ц","у","к","е","н","г","ш","щ","з","х","ъ", "ф","ы","в","а","п","р","о","л","д","ж","э", "я","ч","с","м","и","т","ь","б","ю" ); $str_replace = array( "q","w","e","r","t","y","u","i","o","p","[","]", "a","s","d","f","g","h","j","k","l",";","'", "z","x","c","v","b","n","m",",","." ); return str_replace($str_search, $str_replace, $text); } ?>
смысл, понятен. Надо заменять одну букву на другую.
Проблема в том, что пример чувствителен к регистру . На помощь придут регулярные выражения, но для этого надо модифицировать $str_search, обрамляя его элементы в #й#ui, где ui - это модификатор означающий, что выражение не чувствительно к регистру и работает в кодировке utf-8. Для этого будем в цикле, в зависимости от нужной раскладки менять один из массивов
function switcher ($text,$reverse=false) { $str[0] = array( "й","ц","у","к","е","н","г","ш","щ","з","х","ъ", "ф","ы","в","а","п","р","о","л","д","ж","э", "я","ч","с","м","и","т","ь","б","ю" ); $str[1]= array( "q","w","e","r","t","y","u","i","o","p","[","]", "a","s","d","f","g","h","j","k","l",";","'", "z","x","c","v","b","n","m",",","." ); $out = array(); foreach($str[0] as $i=>$key){ $out[0][$i] = '#'.str_replace(array('.',']','['),array('\.','\]','\['), $str[ $reverse ? 0:1][$i]).'#ui'; $out[1][$i] = $str[$reverse ? 1:0][$i] ; }; return preg_replace($out[0], $out[1], $text); }
в результате код
echo switcher ('hfcrkflrf ЗРЗ');//раскладка ЗРЗ echo switcher ('hfcrkflrf ЗРЗ',1);//hfcrkflrf php
два варианта написания получены, однако они оба бесполезны, потому, как запрос по ним ничего не даст. Нужен третий - комбинированный. Чтобы на выходе давал из hfcrkflrf ЗРЗ = раскладка PHP. Вроде бы все просто, объединить оба массива и пропустить через preg_replace. Однако, тут, как в анекдоте - есть нюанс. Его очень просто продемонстрировать
echo preg_replace(array('#a#','#b#'),array('b','c'),'aaabbbccc');// на выходе дает ccccccccc
т.е. preg_replace заменяет первое вхождение, а затем использует уже полученную строку для второго вхождения. Нам же нужно, чтобы пример выше вывел bbbcccccc.
Из строковых функция php, такое получилось только у strtr
echo strtr('aaabbbccc',array('a'=>'b','b'=>'c'));//bbbcccccc
значит нужен новый массив
$a = array ( 'й' => 'q', 'ц' => 'w', 'у' => 'e', 'к' => 'r', 'е' => 't', 'н' => 'y', 'г' => 'u', 'ш' => 'i', 'щ' => 'o', 'з' => 'p', 'х' => '[', 'ъ' => ']', 'ф' => 'a', 'ы' => 's', 'в' => 'd', 'а' => 'f', 'п' => 'g', 'р' => 'h', 'о' => 'j', 'л' => 'k', 'д' => 'l', 'ж' => ';', 'э' => '\'', 'я' => 'z', 'ч' => 'x', 'с' => 'c', 'м' => 'v', 'и' => 'b', 'т' => 'n', 'ь' => 'm', 'б' => ',', 'ю' => '.', 'q' => 'й', 'w' => 'ц', 'e' => 'у', 'r' => 'к', 't' => 'е', 'y' => 'н', 'u' => 'г', 'i' => 'ш', 'o' => 'щ', 'p' => 'з', '[' => 'х', ']' => 'ъ', 'a' => 'ф', 's' => 'ы', 'd' => 'в', 'f' => 'а', 'g' => 'п', 'h' => 'р', 'j' => 'о', 'k' => 'л', 'l' => 'д', ';' => 'ж', '\'' => 'э', 'z' => 'я', 'x' => 'ч', 'c' => 'с', 'v' => 'м', 'b' => 'и', 'n' => 'т', 'm' => 'ь', ',' => 'б', '.' => 'ю', 'Й' => 'Q', 'Ц' => 'W', 'У' => 'E', 'К' => 'R', 'Е' => 'T', 'Н' => 'Y', 'Г' => 'U', 'Ш' => 'I', 'Щ' => 'O', 'З' => 'P', 'Х' => '[', 'Ъ' => ']', 'Ф' => 'A', 'Ы' => 'S', 'В' => 'D', 'А' => 'F', 'П' => 'G', 'Р' => 'H', 'О' => 'J', 'Л' => 'K', 'Д' => 'L', 'Ж' => ';', 'Э' => '\'', '?' => 'Z', 'ч' => 'X', 'С' => 'C', 'М' => 'V', 'И' => 'B', 'Т' => 'N', 'Ь' => 'M', 'Б' => ',', 'Ю' => '.', 'Q' => 'Й', 'W' => 'Ц', 'E' => 'У', 'R' => 'К', 'T' => 'Е', 'Y' => 'Н', 'U' => 'Г', 'I' => 'Ш', 'O' => 'Щ', 'P' => 'З', '[' => 'Х', ']' => 'Ъ', 'A' => 'Ф', 'S' => 'Ы', 'D' => 'В', 'F' => 'А', 'G' => 'П', 'H' => 'Р', 'J' => 'О', 'K' => 'Л', 'L' => 'Д', ';' => 'Ж', '\'' => 'Э', 'Z' => '?', 'X' => 'ч', 'C' => 'С', 'V' => 'М', 'B' => 'И', 'N' => 'Т', 'M' => 'Ь', ',' => 'Б', '.' => 'Ю', ); echo strtr('hfcКkflrf зрз',$a);// расКладка php
этот вариант помимо всего прочего сохраняет регистр букв. Однако он не дает первых двух вариантов. Итоговый вариант будет выглядеть так
function switcher($text,$arrow=0){ $str[0] = array('й' => 'q', 'ц' => 'w', 'у' => 'e', 'к' => 'r', 'е' => 't', 'н' => 'y', 'г' => 'u', 'ш' => 'i', 'щ' => 'o', 'з' => 'p', 'х' => '[', 'ъ' => ']', 'ф' => 'a', 'ы' => 's', 'в' => 'd', 'а' => 'f', 'п' => 'g', 'р' => 'h', 'о' => 'j', 'л' => 'k', 'д' => 'l', 'ж' => ';', 'э' => '\'', 'я' => 'z', 'ч' => 'x', 'с' => 'c', 'м' => 'v', 'и' => 'b', 'т' => 'n', 'ь' => 'm', 'б' => ',', 'ю' => '.','Й' => 'Q', 'Ц' => 'W', 'У' => 'E', 'К' => 'R', 'Е' => 'T', 'Н' => 'Y', 'Г' => 'U', 'Ш' => 'I', 'Щ' => 'O', 'З' => 'P', 'Х' => '[', 'Ъ' => ']', 'Ф' => 'A', 'Ы' => 'S', 'В' => 'D', 'А' => 'F', 'П' => 'G', 'Р' => 'H', 'О' => 'J', 'Л' => 'K', 'Д' => 'L', 'Ж' => ';', 'Э' => '\'', '?' => 'Z', 'ч' => 'X', 'С' => 'C', 'М' => 'V', 'И' => 'B', 'Т' => 'N', 'Ь' => 'M', 'Б' => ',', 'Ю' => '.',); $str[1] = array ( 'q' => 'й', 'w' => 'ц', 'e' => 'у', 'r' => 'к', 't' => 'е', 'y' => 'н', 'u' => 'г', 'i' => 'ш', 'o' => 'щ', 'p' => 'з', '[' => 'х', ']' => 'ъ', 'a' => 'ф', 's' => 'ы', 'd' => 'в', 'f' => 'а', 'g' => 'п', 'h' => 'р', 'j' => 'о', 'k' => 'л', 'l' => 'д', ';' => 'ж', '\'' => 'э', 'z' => 'я', 'x' => 'ч', 'c' => 'с', 'v' => 'м', 'b' => 'и', 'n' => 'т', 'm' => 'ь', ',' => 'б', '.' => 'ю','Q' => 'Й', 'W' => 'Ц', 'E' => 'У', 'R' => 'К', 'T' => 'Е', 'Y' => 'Н', 'U' => 'Г', 'I' => 'Ш', 'O' => 'Щ', 'P' => 'З', '[' => 'Х', ']' => 'Ъ', 'A' => 'Ф', 'S' => 'Ы', 'D' => 'В', 'F' => 'А', 'G' => 'П', 'H' => 'Р', 'J' => 'О', 'K' => 'Л', 'L' => 'Д', ';' => 'Ж', '\'' => 'Э', 'Z' => '?', 'X' => 'ч', 'C' => 'С', 'V' => 'М', 'B' => 'И', 'N' => 'Т', 'M' => 'Ь', ',' => 'Б', '.' => 'Ю', ); return strtr($text,isset( $str[$arrow] )? $str[$arrow] :array_merge($str[0],$str[1])); }
которая на выходе дает
echo switcher('hfcrkflrf зрз',0);//hfcrkflrf php echo switcher('hfcrkflrf зрз',1);//раскладка зрз echo switcher('hfcrkflrf зрз',2);//раскладка php
вариантов немного прибавилось, но в целом неплохо =)
для интересующихся приведу еще пример с javascript
var switcher = function(text,arrow){ var str = [], newstr = []; str[0] = {'й' : 'q', 'ц' : 'w', 'у' : 'e', 'к' : 'r', 'е' : 't', 'н' : 'y', 'г' : 'u', 'ш' : 'i', 'щ' : 'o', 'з' : 'p', 'х' : '[', 'ъ' : ']', 'ф' : 'a', 'ы' : 's', 'в' : 'd', 'а' : 'f', 'п' : 'g', 'р' : 'h', 'о' : 'j', 'л' : 'k', 'д' : 'l', 'ж' : ';', 'э' : '\'', 'я' : 'z', 'ч' : 'x', 'с' : 'c', 'м' : 'v', 'и' : 'b', 'т' : 'n', 'ь' : 'm', 'б' : ',', 'ю' : '.','Й' : 'Q', 'Ц' : 'W', 'У' : 'E', 'К' : 'R', 'Е' : 'T', 'Н' : 'Y', 'Г' : 'U', 'Ш' : 'I', 'Щ' : 'O', 'З' : 'P', 'Х' : '[', 'Ъ' : ']', 'Ф' : 'A', 'Ы' : 'S', 'В' : 'D', 'А' : 'F', 'П' : 'G', 'Р' : 'H', 'О' : 'J', 'Л' : 'K', 'Д' : 'L', 'Ж' : ';', 'Э' : '\'', '?' : 'Z', 'ч' : 'X', 'С' : 'C', 'М' : 'V', 'И' : 'B', 'Т' : 'N', 'Ь' : 'M', 'Б' : ',', 'Ю' : '.',}; str[1] = { 'q' : 'й', 'w' : 'ц', 'e' : 'у', 'r' : 'к', 't' : 'е', 'y' : 'н', 'u' : 'г', 'i' : 'ш', 'o' : 'щ', 'p' : 'з', '[' : 'х', ']' : 'ъ', 'a' : 'ф', 's' : 'ы', 'd' : 'в', 'f' : 'а', 'g' : 'п', 'h' : 'р', 'j' : 'о', 'k' : 'л', 'l' : 'д', ';' : 'ж', '\'' : 'э', 'z' : 'я', 'x' : 'ч', 'c' : 'с', 'v' : 'м', 'b' : 'и', 'n' : 'т', 'm' : 'ь', ',' : 'б', '.' : 'ю','Q' : 'Й', 'W' : 'Ц', 'E' : 'У', 'R' : 'К', 'T' : 'Е', 'Y' : 'Н', 'U' : 'Г', 'I' : 'Ш', 'O' : 'Щ', 'P' : 'З', '[' : 'Х', ']' : 'Ъ', 'A' : 'Ф', 'S' : 'Ы', 'D' : 'В', 'F' : 'А', 'G' : 'П', 'H' : 'Р', 'J' : 'О', 'K' : 'Л', 'L' : 'Д', ';' : 'Ж', '\'' : 'Э', 'Z' : '?', 'X' : 'ч', 'C' : 'С', 'V' : 'М', 'B' : 'И', 'N' : 'Т', 'M' : 'Ь', ',' : 'Б', '.' : 'Ю',}; for(var j=0;j<=1;j++) if( arrow==undefined||arrow==j ) for(var i=0;i<text.length;i++) if(str[j][text[i]]) newstr[i]=str[j][text[i]]; for(var i=0;i<text.length;i++) if( !newstr[i] ) newstr[i]= text[i]; return newstr.join(''); };
использовать почти также
alert(switcher('hfcrkflrf зрз',0));//hfcrkflrf php alert(switcher('hfcrkflrf зрз',1));//раскладка зрз alert(switcher('hfcrkflrf зрз'));//раскладка php
Комментарии
ЗЫЖ Система комментариев на этом сайте это отдельный баг
Кстати большие буквы заменяю без регулярок - просто продублировал параметры с большими буквами.
---
/**
* Меняет раскладку текста с русской на латинскую
* */
function switchTextToEnglish ($text)
{
$str_search = array(
"й","ц","у","к","е","н","г","ш","щ","з","х","ъ",
"ф","ы","в","а","п","р","о","л","д","ж","э",
"я","ч","с","м","и","т","ь","б","ю",
"Й","Ц","У","К","Е","Н","Г","Ш","Щ","З","Х","Ъ",
"Ф","Ы","В","А","П","Р","О","Л","Д","Ж","Э",
"Я","Ч","С","М","И","Т","Ь","Б","Ю"
);
$str_replace = array(
"q","w","e","r","t","y","u","i","o","p","[","]",
"a","s","d","f","g","h","j","k","l",";","'",
"z","x","c","v","b","n","m",",",".",
"Q","W","E","R","T","Y","U","I","O","P","[","]",
"A","S","D","F","G","H","J","K","L",";","'",
"Z","X","C","V","B","N","M",",","."
);
return str_replace($str_search, $str_replace, $text);
}
/**
* Меняет раскладку текста с латинской на русскую
* */
function switchTextToRussian ($text)
{
$str_search = array(
"q","w","e","r","t","y","u","i","o","p","[","]",
"a","s","d","f","g","h","j","k","l",";","'",
"z","x","c","v","b","n","m",",",".",
"Q","W","E","R","T","Y","U","I","O","P","[","]",
"A","S","D","F","G","H","J","K","L",";","'",
"Z","X","C","V","B","N","M",",","."
);
$str_replace = array(
"й","ц","у","к","е","н","г","ш","щ","з","х","ъ",
"ф","ы","в","а","п","р","о","л","д","ж","э",
"я","ч","с","м","и","т","ь","б","ю",
"Й","Ц","У","К","Е","Н","Г","Ш","Щ","З","Х","Ъ",
"Ф","Ы","В","А","П","Р","О","Л","Д","Ж","Э",
"Я","Ч","С","М","И","Т","Ь","Б","Ю"
);
return str_replace($str_search, $str_replace, $text);
}
/**
* Формирует множественный фильтр по строке с логикой "ИЛИ", содержит
* - оригинальный запрос
* - запрос в русской раскладке
* - запрос в латинской раскладке
*
* Usage example:
*
* $arFilter = array(
* ...
* );
*
* $arFilter[] = prepareTextQueryMultiLangFilter($arParams["QUERY"] );
* */
function prepareTextQueryMultiLangFilter($query)
{
$result = array(
"LOGIC" => "OR",
"SEARCHABLE_CONTENT" => array(
"%" . $query . "%",
"%" . switchTextToEnglish($query) . "%",
"%" . switchTextToRussian($query) . "%",
),
);
return $result;
}
/**
* Punto switcher (0: rus -> eng, 1: eng -> rus, false -> eng & rus -> rus & eng)
*
* @param string $text
* @param int|bool $arrow
* @return string
*/
private function stringSwitcher($text, $arrow = 0): string
{
$str[0] = array(
'й' => 'q', 'ц' => 'w', 'у' => 'e', 'к' => 'r', 'е' => 't', 'н' => 'y', 'г' => 'u', 'ш' => 'i', 'щ' => 'o', 'з' => 'p', 'х' => '[', 'ъ' => ']', 'ф' => 'a', 'ы' => 's', 'в' => 'd',
'а' => 'f', 'п' => 'g', 'р' => 'h', 'о' => 'j', 'л' => 'k', 'д' => 'l', 'ж' => ';', 'э' => '\'', 'я' => 'z', 'ч' => 'x', 'с' => 'c', 'м' => 'v', 'и' => 'b', 'т' => 'n', 'ь' => 'm',
'б' => ',', 'ю' => '.', 'Й' => 'Q', 'Ц' => 'W', 'У' => 'E', 'К' => 'R', 'Е' => 'T', 'Н' => 'Y', 'Г' => 'U', 'Ш' => 'I', 'Щ' => 'O', 'З' => 'P', 'Х' => '[', 'Ъ' => ']', 'Ф' => 'A',
'Ы' => 'S', 'В' => 'D', 'А' => 'F', 'П' => 'G', 'Р' => 'H', 'О' => 'J', 'Л' => 'K', 'Д' => 'L', 'Ж' => ';', 'Э' => '\'', '?' => 'Z', 'ч' => 'X', 'С' => 'C', 'М' => 'V', 'И' => 'B',
'Т' => 'N', 'Ь' => 'M', 'Б' => ',', 'Ю' => '.',
);
$str[1] = array(
'q' => 'й', 'w' => 'ц', 'e' => 'у', 'r' => 'к', 't' => 'е', 'y' => 'н', 'u' => 'г', 'i' => 'ш', 'o' => 'щ', 'p' => 'з', '[' => 'х', ']' => 'ъ', 'a' => 'ф', 's' => 'ы', 'd' => 'в',
'f' => 'а', 'g' => 'п', 'h' => 'р', 'j' => 'о', 'k' => 'л', 'l' => 'д', ';' => 'ж', '\'' => 'э', 'z' => 'я', 'x' => 'ч', 'c' => 'с', 'v' => 'м', 'b' => 'и', 'n' => 'т', 'm' => 'ь',
',' => 'б', '.' => 'ю', 'Q' => 'Й', 'W' => 'Ц', 'E' => 'У', 'R' => 'К', 'T' => 'Е', 'Y' => 'Н', 'U' => 'Г', 'I' => 'Ш', 'O' => 'Щ', 'P' => 'З', '[' => 'Х', ']' => 'Ъ', 'A' => 'Ф',
'S' => 'Ы', 'D' => 'В', 'F' => 'А', 'G' => 'П', 'H' => 'Р', 'J' => 'О', 'K' => 'Л', 'L' => 'Д', ';' => 'Ж', '\'' => 'Э', 'Z' => '?', 'X' => 'ч', 'C' => 'С', 'V' => 'М', 'B' => 'И',
'N' => 'Т', 'M' => 'Ь', ',' => 'Б', '.' => 'Ю',
);
return strtr($text, $str[$arrow] ?? \array_merge($str[0], $str[1]));
}