В очередной раз написав "поиск" для проекта задумался о его удобстве. Очень малое число людей владеет слепым методом печати, поэтому вводят не глядя на экран. В результате появляются такие вещи типа «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( '' ); }; |
использовать почти также
1 2 3 | 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]));
}