Блог


Транслитерация

Статья в рамках программы переноса материалов со старого сайта.

Транслитерация - есть передача звучания речи на одном языке посредством записи ее символами алфавита другого языка. 

На практике такая необходимость встречается не часто, но для аргументации приведу пару примеров:
1. Передача русской речи с компьютера из-за границы, где не предусмотрена русская раскладка клавиатуры.
2. Оформление заголовков (например, в библиотеках), где название не должно переводиться.
3. Написание фамилии в загран-паспорте.
Ну и прочее.

В сайтостроении это действие нужно там, где нельзя использовать кирилицу, а исходный текст именно на ней. Допустим при загрузке файлов обозначить принадлежность к логину. Ежели тот допускает русские имена, то файловая система не столь к ним приветлива.
Или часто делается по логину страничка.

Транслитерация - вещь зерьёзная. Причастность к общепринятым нормам, таким как правописание, накладывает строгие рамки на оформление. Существует даже ГОСТ, это дело регламентирующий. Вот, кому интересно, ознакомьтесь: ГОСТ 7.79-2000 (ИСО 9-95)

Что представляет из себя механизм транслитерации? Все очень просто - каждой букве одного алфавита сответствует буква другого алфавита с похожим звучанием. Вот так:
а->a
б->b
в->v
...
И так далее. Вот можно попробовать.



Не откладывая в долгий ящик, создаем соответствующие массивы

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
<?php

   
    $L
['ru'] = array( 
                        
'А''Б''В''Г''Д''Е''Ё',  
                        
'Ж''З''И''Й''К''Л''М'
                        
'Н''О''П''Р''С''Т''У',  
                        
'Ф''Х''Ц''Ч''Ш''Щ''Ы'
                        
'Ъ''Ь''Э''Ю''Я'
                        
'а''б''в''г''д''е''ё',  
                        
'ж''з''и''й''к''л''м'
                        
'н''о''п''р''с''т''у',  
                        
'ф''х''ц''ч''ш''щ''ы'
                        
'ъ''ь''э''ю''я' 
                    
); 

    
$L['en'] = array( 
                        
"A",  "B",  "V",  "G",  "D",  "E",   "YO",  
                        
"ZH""Z",  "I",  "J",  "K",  "L",   "M",  
                        
"N",  "O",  "P",  "R",  "S",  "T",   "U",  
                        
"F" "X" "CZ""CH""SH""SHH""Y'",  
                        
"''""'",  "E'""YU""YA"
                        
"a",  "b",  "v",  "g",  "d",  "e",   "yo",  
                        
"zh""z",  "i",  "j",  "k",  "l",   "m",  
                        
"n",  "o",  "p",  "r",  "s",  "t",   "u",  
                        
"f" "x" "cz""ch""sh""shh""y'",  
                        
"''""'",  "e'""yu""ya" 
                    
);

Теперь мы имеем два массива в одинаковом порядке. То есть, можем сопоставлять элементы.
Ну что, давайте сделаем функцию, которая и будет производить транслитерирование.

Принимать эта функция будет сам текст и параметр, указывающий на направление перевода. По умолчанию перевод будем делать в направлении кириллица-латиница:

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
<?php


    
function TranslateIt($text$direct="ru_en"
    { 
    
/** 
    * Массивы соответствия сочетаний 
    */ 
        
$L['ru'] = ... ; // не будем повторяться 
        
$L['en'] = ... ; 

        
// В зависимости от параметра $direct, конвертируем 
        // великий могучий в хилый и немощный... 
        
if($direct == "ru_en"
            
$translated str_replace($L['ru'], $L['en'], $text); 
         
        
// ...или наоборот 
        
elseif($direct == "en_ru"
            
$translated str_replace($L['en'], $L['ru'], $text); 
         
        
// Возвращаем получателю. 
        
return $translated
    } 

Остановимся на функции str_replace(). Она принимает три параметра: искомую строку, строку замены и, собственно, строку-пациента. Однако, она также может в качестве первых двух параметров принимать массивы строк и в этом случае ищет совпадения всех элементов первого массива, сопоставляя им элементы второго массива по ключу (то есть по позиции элемента в массиве). Это значит, что если в массиве искомых значений есть буква Г (4-я по порядку), которая присутствует в строке-пациенте, то str_replace() заменит все ее вхождения на G (также, 4-я по порядку).

Замечательно!
Суем транслитератору любые русские слова, на какие фантазии хватает, и получаем результат на транслите.

А что, если попробуем обратное преобразование?
Суем строку "YA - velikij programmist!" и получаем "YА - великий программист!", что в корне не верно и, похоже, во всех смыслах...

В чем же дело? А в том, что функция str_replace() перебирает значения искомого массива по порядку их следования и, найдя первое же соответствие, начинает поиск следующего элемента. Получается, что A она нашла сразу и заменила на русский эквивалент и когда дошла до сочетания YA в массиве, в тексте его уже не было.

Что делать? Естесственно, заставить рассматривать сочетания букв раньше, чем односимвольные буквы. Поправим наши массивы. Заодно поменяв местами Ш и Щ, Ъ и Ь - по той же причине. А также обратим внимание, что, например, буква Ю может выглядеть на транслите как YU, так и Yu.

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
<?php

   
    $L
['ru'] = array( 
                        
'Ё''Ж''Ц''Ч''Щ''Ш''Ы',  
                        
'Э''Ю''Я''Ё''Ж''Ц''Ч',  
                        
'Щ''Ш''Ю''Я''ё''ж''ц',  
                        
'ч''щ''ш''ы''э''ю''я',  
                        
'А''Б''В''Г''Д''Е''З',  
                        
'И''Й''К''Л''М''Н''О',  
                        
'П''Р''С''Т''У''Ф''Х',  
                        
'Ъ''Ь''а''б''в''г''д',  
                        
'е''з''и''й''к''л''м',  
                        
'н''о''п''р''с''т''у',  
                        
'ф''х''ъ''ь' 
                    
); 

                 
    
$L['en'] = array( 
                        
"YO""ZH""CZ",  "CH""SHH""SH""Y'",  
                        
"E'""YU""YA",  "Yo""Zh",  "Cz""Ch",  
                        
"Sh""Sh""Yu",  "Ya""yo",  "zh""cz",  
                        
"ch""shh""sh""y'""e'",  "yu""ya",  
                        
"A",  "B" "V" ,  "G",  "D",   "E",  "Z",  
                        
"I",  "J",  "K",   "L",  "M",   "N",  "O",  
                        
"P",  "R",  "S",   "T",  "U",   "F",  "X",  
                        
"''""'",  "a",   "b",  "v",   "g",  "d",  
                        
"e",  "z",  "i",   "j",  "k",   "l",  "m",  
                        
"n",  "o",  "p",   "r",  "s",   "t",  "u",  
                        
"f",  "x",  "''",  "'" 
                    
);

В принципе, теперь все должно замечательно работать. Если бы не одна тонкость. Дело в том, что символ ' (апостроф) не имеет другого регистра. Это значит, что мягкий и твердый знаки всегда будут в верхнем регистре, ведь до них функция str_replace() доберется раньше. И простым перемещением тут уже не обойтись. Более того, Ъ и Ь в нижнем регистре можно вообще удалить из массивов.

Давайте рассуждать логически. Когда в тексте встречаются эти знаки? Правильно, после согласных букв. Значит, если предыдущая буква в нижнем регистре, то и знак, следующий за ней тоже должен быть в нижнем. Остается только корректно составить шаблон регулярного выражения и воспользоваться функцией preg_replace(). Вот так:

1
 2
 3
 4
 5

    $translated 
preg_replace('/(?<=[а-яё])Ь/u''ь'$translated); 
    
$translated preg_replace('/(?<=[а-яё])Ъ/u''ъ'$translated);

Шаблоны можно расшифровать так: мягкий/твердый знак, перед которым есть символ, входящий в диапазон а-я. А поскольку буквы в верхнем регистре в этот диапазон не входят, то после них знак так и останется в верхнем регистре. Добавим к этому форму и можно пробовать. Вот полный код нашего транслитератора:

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
<?php

   
/** 
* Transliteration function 
* Функция транслитерации текста 
* @param string $text 
* @param string $direct 
* @return string 
* @author IT studio IRBIS-team 
* @copyright © 2010 IRBIS-team 
*/ 
    
function TranslateIt($text$direct 'ru_en'
    { 
     
     
        
$L['ru'] = array( 
                          
'Ё''Ж''Ц''Ч''Щ''Ш''Ы',  
                          
'Э''Ю''Я''ё''ж''ц''ч',  
                          
'ш''щ''ы''э''ю''я''А',  
                          
'Б''В''Г''Д''Е''З''И',  
                          
'Й''К''Л''М''Н''О''П',  
                          
'Р''С''Т''У''Ф''Х''Ъ',  
                          
'Ь''а''б''в''г''д''е',  
                          
'з''и''й''к''л''м''н',  
                          
'о''п''р''с''т''у''ф',  
                          
'х''ъ''ь' 
                        
); 

                 
        
$L['en'] = array( 
                          
"YO""ZH",  "CZ""CH""SHH","SH""Y'",  
                          
"E'""YU",  "YA""yo""zh""cz""ch",  
                          
"sh""shh""y'""e'""yu""ya""A",  
                          
"B" "V" ,  "G",  "D",  "E",  "Z",  "I",  
                          
"J",  "K",   "L",  "M",  "N",  "O",  "P",  
                          
"R",  "S",   "T",  "U",  "F",  "X",  "''"
                          
"'",  "a",   "b",  "v",  "g",  "d",  "e",  
                          
"z",  "i",   "j",  "k",  "l",  "m",  "n",   
                          
"o",  "p",   "r",  "s",  "t",  "u",  "f",   
                          
"x",  "''",  "'" 
                        
); 
                  
         
        
// Конвертируем хилый и немощный в великий могучий... 
        
if($direct == 'en_ru'
        { 
            
$translated str_replace($L['en'], $L['ru'], $text);         
            
// Теперь осталось проверить регистр мягкого и твердого знаков. 
            
$translated preg_replace('/(?<=[а-яё])Ь/u''ь'$translated); 
            
$translated preg_replace('/(?<=[а-яё])Ъ/u''ъ'$translated); 
        } 
        else 
// И наоборот 
            
$translated str_replace($L['ru'], $L['en'], $text);         
        
// Возвращаем получателю. 
        
return $translated
    } 

    
$string = !empty($_POST['string']) ? $_POST['string'] : NULL;      
    
$direct = !empty($_POST['direct']) ? $_POST['direct'] : NULL
    
$text   = !empty($_POST['ok']) ? TranslateIt($string$direct) : NULL
         
?> 
<FORM action="" method="post"> 
    Текст<br> 
 <textarea name="string" cols="40" rows="10"><?php echo  htmlspecialchars($text?></textarea><br> 
    Перевод  
    <SELECT name="direct"> 
        <OPTION value="ru_en">кириллица-латиница</OPTION> 
        <OPTION value="en_ru">латиница-кириллица</OPTION> 
    </SELECT><br> 
    <INPUT type="submit" name="ok" value="Перевести"></INPUT> 
</FORM>

Вот, собственно, и все.

Быков Илья aka Shturman

Теги: PHP | seo

Комментарии (2)

Vitaly Grakho
25-12-2013
В этом кусочке
1
2
3

'/(?<=[а-яё])Ъ/u'

букву "ё", наверное, можно убрать? Ведь после гласных ни мягкий, ни твёрдый знак не ставятся.
twin
25-12-2013
Ну это не обязательно может быть словом. Может это набор букв. Пароль допустим или шифр какой-нибудь))) Мало ли какие могут быть ситуации. Нам важно, чтобы любой текст можно было конвертировать туда-обратно.

 
Наверх