Возможно, кто-то еще помнит, как писали SMS, а иногда и письма, «транслитом». Но зачем транслитерация сегодня, когда везде уже unicode? К сожалению, унаследованные приложения выходят из эксплуатации намного медленнее, чем хотелось бы. Например, и сегодня используются томографы, не допускающие кириллицу в именах пациентов. При том, что информационная система, используемая тем же отделением, прекрасно кириллицу понимает. И оператору томографа нужно не просто позвать пациента на исследование, но и правильно записать его фамилию в какие-нибудь документы. Похожие ситуации могут встретится в разных местах.

То есть, возникает задача как-то передать текстовые данные в унаследованную систему, чтобы:
  • человек — оператор унаследованной системы смог прочесть полученный текст «по звучанию»
  • при необходимости можно было бы однозначно восстановить исходный кириллический текст

Чтобы не было скучно, добавим более подробных требований, связанных с совместимостью и простотой для человека:
  1. использовать только буквы в узком смысле, без знаков препинания и диакритических элементов (это заодно позволит сохранить регистр)
  2. каждую исходную букву преобразовывать независимо от остальных (без сложностей вроде «в начале / в конце слова» и т.п.)
  3. замены как можно более короткие, в идеале одно-буквенные
  4. правила обратного преобразованния как можно проще, например, замены должны соответствовать условию Фано
  5. близкие по звучанию замены, в представлении «обычного человека» — на практике это некая смесь из латыни, английской, французской, немецкой и, иногда, испанской фонетики

Конечно, перечисленное не совсем требования (кроме первых двух), а, скорее, эвристики.

Можно найти много готовых вариантов транслитерации кириллицы в латиницу. Но среди них не нашлось ничего, что бы удовлетворяло всем требованиям в приемлемой степени. То использует диакритические символы, как стандарты, то выбрасывает буквы (обычно «Ъ»), то предлагают необратимые (щ —> shch) или фонетически дикие (ш —> w) варианты замены, или имеют другие фатальные недостатки.

Значит, делаем свой велосипед. Собственно, нужно составить таблицу соответствия, и описать алгоритм преобразования туда и обратно.

Таблица


Начнем со всем очевидных одно-буквенных замен:
А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
A B V G D E Z I K L M N O P R S T U F

Помня о требовании возможно коротких замен, и поскольку для «С» используем «S», с чистой совестью используем для «Ц» символ «C».

Для оставшихся букв традиция (и просто нехватка символов латиницы) велит нам использовать двух-буквенные сочетания. Для простоты прямого и, в особенности, обратного преобразования, хорошо бы, чтобы сочетания образовывали символы, не используемые вне сочетаний. По условию Фано, такой особый символ должен стоять в начале сочетания, но традиция слишком сильна и букву «H» будем писать все-таки в конце сочетания. Но, если отдельно символ «H» не использовать и разрешить алгоритму преобразования «возвращаться» (на самом деле, — запоминать) к предыдущему входному символу, для постфиксных сочетаний можно считать выполненным «перевернутый» аналог условия Фано. То есть алгоритм сможет их однозначно определять.

Особый символ для согласных везде один — «H». А для гласных есть два варианта: «Y» и «J». Хотя «Y» привычнее, он также часто используется отдельно, для «Й» или для «Ы». А «J» скорее воспринимается как чисто вспомогательный символ.

Решено, используем для гласных «J». А кстати освободившийся «Y» используем для «Й».

Раз «J» теперь особый символ, использовать его для «Ж» нельзя, и остается только «ZH». Аналогично, для «Х» нельзя использовать «H», и остается только «KH».

Теперь можем записать общепринятые и выбранные сочетания и одиночные символы:
А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
A B V G D E ZH Z I Y K L M N O P R S T U F KH C CH SH EH JU JA

Распространенные и хорошие (в смысле наших требований) замены здесь кончились, и мы вступаем на зыбкую почву «отсебятины», аналогий и компромиссов.

Начнем с «Ы». «Y» уже занят (помним про обратимость), да и фонетически это плохая замена. Посмотрим на решение для «Э» (взято, между прочим, из ISO/R 9, 1968 г.). По аналогии «Ы» должно заменятся на «IH». Странно, что такой вариант нигде не встретился.

С «Ё» ситуация тоже странная. Есть понятный, но не подходящий нам вариант «E». И есть фонетический вариант «JO». Но в русском алфавите «Ё» не случайно сделана на основе «Е», а не «О». «Ё» часто чередуется с «Е», например «клён — кленовый», и никогда не чередуется с «О». Это получается еще одна эвристика — «алфавитная» (не фонетическая и не графическая) близость букв. В результате для «Ё» конструируем замену «JE».
Сделаем паузу:
А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
A B V G D E JE ZH Z I Y K L M N O P R S T U F KH C CH SH IH EH JU JA

Как хорошо было бы на этом остановится и сказать, что задача в первом приближении решена. Но остались еще три буквы, без которых никак не обойтись. Для оставшихся букв нет никаких адекватных вариантов. Знаки обычно заменяют апострофами, а буквенные замены либо просто произвольны, либо «остроумны», вроде «ь» —>«q». Для «Щ» замена без диакритических знаков обычно длиной в 3 — 4 символа, и с ней еще будут проблемы.

После долгих исканий и страданий, пришлось остановится на таком рассуждении: для букв, которым не соответствуют звуки, нельзя использовать буквы, для которых звуки есть. И нам остаются только «специальные» символы для образования сочетаний. Но по условию Фано их нельзя использовать отдельно, сочетания станут неоднозначны.

Выход — использовать сочетания специальных символов друг с другом. Это, видимо, еще немного усложнит алгоритм преобразования, но кажется возможным сохранить однозначность.

Для твердого знака (он у нас только разделительный) интуитивно кажется уместной замена «HH» (не читается, как пауза, разделение).

А для мягкого знака цепочки ассоциаций («J» —> йотированные гласные —> смягчение предыдущей согласной) + («H» —> разделение) приводят к замене «JH».

Не назовешь красивым решением, но среди гнилых яблок выбор не велик.

К сожалению, такой выбор делает невозможным использовать замену «Щ» —> «SHH». Последовательность «SHH» будет означать «СЪ», и такое сочетание встречается в русском языке (например, «съезд»). Тут снова нет симпатичных решений, и надо искать хоть как-то мотивированные. Звук «Щ» близок к смягченному «Ш», и по аналогии с мягким знаком можно это изобразить префиксным «J». Понимаю, что сейчас ссылаюсь сам на себя, что код все равно длинны 3 и не стандартный. Но, как говорится, «других писателей у нас для вас нЭт».

В результате:
А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
A B V G D E JE ZH Z I Y K L M N O P R S T U F KH C CH SH JSH HH IH JH EH JU JA

Алгоритм


Преобразование из кириллицы в латиницу тривиально. На регистр не обращаем внимания для краткости.
Код на Java
public class Translit {
	public static String cyr2lat(char ch){
		switch (ch){
			case 'А': return "A";
			case 'Б': return "B";
			case 'В': return "V";
			case 'Г': return "G";
			case 'Д': return "D";
			case 'Е': return "E";
			case 'Ё': return "JE";
			case 'Ж': return "ZH";
			case 'З': return "Z";
			case 'И': return "I";
			case 'Й': return "Y";
			case 'К': return "K";
			case 'Л': return "L";
			case 'М': return "M";
			case 'Н': return "N";
			case 'О': return "O";
			case 'П': return "P";
			case 'Р': return "R";
			case 'С': return "S";
			case 'Т': return "T";
			case 'У': return "U";
			case 'Ф': return "F";
			case 'Х': return "KH";
			case 'Ц': return "C";
			case 'Ч': return "CH";
			case 'Ш': return "SH";
			case 'Щ': return "JSH";
			case 'Ъ': return "HH";
			case 'Ы': return "IH";
			case 'Ь': return "JH";
			case 'Э': return "EH";
			case 'Ю': return "JU";
			case 'Я': return "JA";
			default: return String.valueOf(ch);
		}
	}

	public static String cyr2lat(String s){
		StringBuilder sb = new StringBuilder(s.length()*2);
		for(char ch: s.toCharArray()){
			sb.append(cyr2lat(ch));
		}
		return sb.toString();
	}
}

Для примера результата пара известных панграмм:
SHirokaja ehlektrifikacija juzhnihkh guberniy dast mojshnihy tolchok podhhjemu seljhskogo khozjaystva.
Shheshjh zhe ejshje ehtikh mjagkikh francuzskikh bulok da vihpey chaju.

Выглядит не очень, но основное назначение этого варианта транслитерации все-таки ФИО:
Aleksandr Ivanovich Lebedjh
Georgiy Konstantinovich ZHukov

С обратным преобразованием куда интереснее. Особенно учитывая, что его хорошо бы объяснить человеку (не из IT) для выполнения «в уме».
Видимо, начать надо с особых случаев.
  • Поскольку читаем мы слева направо, первым дело обращаем внимание на символ «J». За ним обязательно должен идти один из пяти символов: «E», «H», «U», «A» или «S» (за «S» должен в этом случае обязательно быть еще «H»), и получается то, что в таблице для двух-трех буквенных сочетаний.
  • Если «J» нет, смотрим, не идет ли следом за символом буква «H». Тут самый тяжелый для внимания момент: в этот случай не должен попасть вариант, когда третьим символом снова идет «H» (это код «HH»). То есть видеть и анализировать надо три символа подряд. Вот где нарушение условия Фано аукнулось (хорошо, что один раз).
  • Если ни «J», ни одиночного «H» поблизости от символа не обнаружилось, смело заменяем его по таблице как отдельную букву.

После недолгой тренировки, как показывает практика, люди способны выполнять обратное преобразования вручную. Но заставлять их это делать без особой необходимости, конечно, не надо. Можно и автоматизировать (опять же для простоты только для строки и в верхнем регистре):
Код на Java
	public static String lat2cyr(String s){
		StringBuilder sb = new StringBuilder(s.length());
		int i = 0;
		while(i < s.length()){// Идем по строке слева направо. В принципе, подходит для обработки потока
			char ch = s.charAt(i);
			if(ch == 'J'){ // Префиксная нотация вначале
				i++; // преходим ко второму символу сочетания
				ch = s.charAt(i);
				switch (ch){
					case 'E': sb.append( 'Ё'); break;
					case 'S':
						sb.append( 'Щ');
						i++; // преходим к третьему символу сочетания
						if(s.charAt(i) != 'H') throw new IllegalArgumentException("Illegal transliterated symbol at position "+i);// вариант третьего символа только один
						break;
					case 'H': sb.append( 'Ь'); break;
					case 'U': sb.append( 'Ю'); break;
					case 'A': sb.append( 'Я'); break;
					default: throw new IllegalArgumentException("Illegal transliterated symbol at position "+i);
				}
			}else if(i+1 < s.length() && s.charAt(i+1)=='H' && !(i+2 < s.length() && s.charAt(i+2)=='H')){// Постфиксная нотация, требует информации о двух следующих символах. Для потока придется сделать обертку с очередью из трех символов.
				switch (ch){
					case 'Z': sb.append( 'Ж'); break;
					case 'K': sb.append( 'Х'); break;
					case 'C': sb.append( 'Ч'); break;
					case 'S': sb.append( 'Ш'); break;
					case 'E': sb.append( 'Э'); break;
					case 'H': sb.append( 'Ъ'); break;
					case 'I': sb.append( 'Ы'); break;
					default: throw new IllegalArgumentException("Illegal transliterated symbol at position "+i);
				}
				i++; // пропускаем постфикс
			}else{// одиночные символы
				switch (ch){
					case 'A': sb.append( 'А'); break;
					case 'B': sb.append( 'Б'); break;
					case 'V': sb.append( 'В'); break;
					case 'G': sb.append( 'Г'); break;
					case 'D': sb.append( 'Д'); break;
					case 'E': sb.append( 'Е'); break;
					case 'Z': sb.append( 'З'); break;
					case 'I': sb.append( 'И'); break;
					case 'Y': sb.append( 'Й'); break;
					case 'K': sb.append( 'К'); break;
					case 'L': sb.append( 'Л'); break;
					case 'M': sb.append( 'М'); break;
					case 'N': sb.append( 'Н'); break;
					case 'O': sb.append( 'О'); break;
					case 'P': sb.append( 'П'); break;
					case 'R': sb.append( 'Р'); break;
					case 'S': sb.append( 'С'); break;
					case 'T': sb.append( 'Т'); break;
					case 'U': sb.append( 'У'); break;
					case 'F': sb.append( 'Ф'); break;
					case 'C': sb.append( 'Ц'); break;
					default: sb.append(ch);
				}
			}

			i++; // переходим к следующему символу
		}
		return sb.toString();
	}

Итог


Казалось бы, простая и давно решенная задача, а какой простор для творчества и обсуждений.

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

Надеюсь, кому-нибудь решение покажется полезным, а путь к нему — занятным.

Дополнение


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

Есть стандарты. Ни один не соответствует требованиям.
Надо выбрать один стандарт и минимально его модифицировать, только для соответствия требованиям.
Модификации однозначно определяются по цепочке. Если Вам не нравится результат, напишите, пожалуйста, с какого пункта цепочки Вы не согласны.
Для обоснования решений немного теории.
Транслитерация — точная передача знаков одной письменности знаками другой письменности.
Не путать с фонетической транскрипцией — передача звучания поощряется, но не гарантирована.
Самый низкий приоритет имеют соображения графического сходства символов. Например передача буквы ха как икс — фонетически не приемлема.

Транслитерацию можно рассматривать как кодирование символов исходного алфавита кодами переменной длинны из символов целевого алфавита. Кодом может быть:
  1. одиночные символы
  2. некий префикс и следующий за ним базовый символ
  3. базовый символ и следующий за ним некий постфикс
  4. базовый символ и c префиксом и с постфиксом

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

Для «легкой обратимости» кодов введем такое условие:
никакой код не должен начинаться с постфикса и не должен заканчиваться префиксом.

Это моё обобщение префиксного кода.
При соблюдении такого условия можно утверждать, что в любом фрагменте результирующей последовательности не будет длинных «ложных кодов». То есть понятно, что можно отрезать префикс или постфикс, и оставшийся базовый символ совпадет с одиночным.
Этого не избежать и это придется помнить. Но не случится такого, что кусочек составного года считается вместе с соседним одиночным символом как незапланированный составной код.
Например, пусть мы используем код «S», код «SH» и код «HH» (нарушает условие, начинается с постфикса). Тогда в последовательности «SHH» (третий и первый коды) можно выделить фрагмент «SH» (соответствует второму коду).
Для префиксов нарушение условия «легкой обратимости» не так неприятно (разница потому, разбор идет слева направо). Но тоже затрудняет восприятие «на глаз» — при беглом просмотре мы считываем слово целиком, а не последовательно, и можем «зацепиться» за случайное сочетание.
Частным следствием введенного условия является запрет на использование префикса или постфикса как одиночных символов.

Для кириллицы и латиницы постфикс — это без вариантов «H».
Префикс бывает «Y» или «J». Если использовать префикс «Y», его нельзя будет применять для передачи «Й» или «Ы». То есть для двух букв (а «Й» довольно частая) придется придумать не стандартные, далекие от фонетики, и скорее всего длинные коды.
С «J» проблем нет. Отдельно этот символ применять и не хотелось.

I. Выберем отправной стандарт.
Самый фонетически верный, конечно, BGN. Но BGN принципиально (даже нарочито) не обратимый.
Самый близкий к базовой латинице и к обратимости, на мой взгляд, «ГОСТ 16876-71 / таблица 2», его и выберем.
...?
Спросите, почему не актуальный сейчас «ГОСТ 7.79-2000 / система Б». В основном за «Х» --> «X» и «Й» --> «J». Ну и сегодня актуальный — а завтра, как предыдущий ГОСТ.
А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
A B V G D E JO ZH Z I JJ K L M N O P R S T U F KH C CH SH SHH ? Y ? EH JU JA

Схема не идеальна в плане наших требований. Придется менять.
II. Первым бросается в глаза «JJ». Почему это плохо, можно посмотреть в «теоретическом» спойлере. Следуем правилу «в любой непонятной ситуации смотри на BGN». То есть «Й» --> «Y».
III. Теперь осталась без кода «Ы». BGN не помогает. Есть фонетическая аналогия в парах «И-Ы» и «Е-Э». Для получения кода буквы «Э» стандарт добавляет к коду «Е» постфикс. Поступим также: «Ы» --> «IH».
IV. Остались не-буквенные замены для «Ь» и «Ъ». Чтобы не разрушить фонетику, можем использовать только префиксы и постфиксы.
V. Заметим, что никто не запрещал (в «теоретическом» спойлере) использовать постфикс в качестве базового символа в сочетаниях с префиксом (как минимум), и наоборот. То есть у нас есть коды «JH», «JHH» и «JJH».
VI. Осталось распределить это богатство. Более частому «Ь» — самый короткий код: «Ь» --> «JH».
VII. У «Ъ» нет звука, «Н» легче не озвучивать при чтении. Так что выберем из оставшегося код, где больше «Н»: «Ъ» --> «JHH».

Получилось:
А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
A B V G D E JO ZH Z I Y K L M N O P R S T U F KH C CH SH SHH JHH IH JH EH JU JA

Код «SHH» единственный использует постфикс длины 2. Но общая длина кода всего 3, буква редкая. Обратимость не нарушается (и даже «легкая обратимость»).
Больше ничего в стандарте трогать нет необходимости.

Код на Java для иллюстрации
package tools;

import static java.lang.Character.toUpperCase;

/**
 * Обратимая транслитерация кириллицы в латиницу
 * Created by vladimir on 25.08.15.
 */
public class Translit {

	public static String lat2cyr(String s){
		StringBuilder sb = new StringBuilder(s.length());
		int i = 0;
		while(i < s.length()){// Идем по строке слева направо. В принципе, подходит для обработки потока
			char ch = s.charAt(i);
			boolean lc = Character.isLowerCase(ch); // для сохранения регистра
			ch = toUpperCase(ch);
			if(ch == 'J'){ // Префиксная нотация вначале
				i++; // преходим ко второму символу сочетания
				ch = toUpperCase(s.charAt(i));
				switch (ch){
					case 'O': sb.append(ch('Ё', lc)); break;
					case 'H':
						if(i+1 < s.length() && toUpperCase(s.charAt(i+1))=='H') { // проверка на постфикс (вариант JHH)
							sb.append(ch('Ъ', lc));
							i++; // пропускаем постфикс
						}else{
							sb.append(ch('Ь', lc));
						}
						break;
					case 'U': sb.append(ch('Ю', lc)); break;
					case 'A': sb.append(ch('Я', lc)); break;
					default: throw new IllegalArgumentException("Illegal transliterated symbol '"+ch+"' at position "+i);
				}
			}else if(i+1 < s.length() && toUpperCase(s.charAt(i+1))=='H' ){// Постфиксная нотация, требует информации о двух следующих символах. Для потока придется сделать обертку с очередью из трех символов.
				switch (ch){
					case 'Z': sb.append(ch('Ж', lc)); break;
					case 'K': sb.append(ch('Х', lc)); break;
					case 'C': sb.append(ch('Ч', lc)); break;
					case 'S':
						if(i+2 < s.length() && toUpperCase(s.charAt(i+2))=='H') { // проверка на двойной постфикс
							sb.append(ch('Щ', lc));
							i++; // пропускаем первый постфикс
						}else{
							sb.append(ch('Ш', lc));
						}
						break;
					case 'E': sb.append(ch('Э', lc)); break;
					case 'I': sb.append(ch('Ы', lc)); break;
					default: throw new IllegalArgumentException("Illegal transliterated symbol '"+ch+"' at position "+i);
				}
				i++; // пропускаем постфикс
			}else{// одиночные символы
				switch (ch){
					case 'A': sb.append(ch('А', lc)); break;
					case 'B': sb.append(ch('Б', lc)); break;
					case 'V': sb.append(ch('В', lc)); break;
					case 'G': sb.append(ch('Г', lc)); break;
					case 'D': sb.append(ch('Д', lc)); break;
					case 'E': sb.append(ch('Е', lc)); break;
					case 'Z': sb.append(ch('З', lc)); break;
					case 'I': sb.append(ch('И', lc)); break;
					case 'Y': sb.append(ch('Й', lc)); break;
					case 'K': sb.append(ch('К', lc)); break;
					case 'L': sb.append(ch('Л', lc)); break;
					case 'M': sb.append(ch('М', lc)); break;
					case 'N': sb.append(ch('Н', lc)); break;
					case 'O': sb.append(ch('О', lc)); break;
					case 'P': sb.append(ch('П', lc)); break;
					case 'R': sb.append(ch('Р', lc)); break;
					case 'S': sb.append(ch('С', lc)); break;
					case 'T': sb.append(ch('Т', lc)); break;
					case 'U': sb.append(ch('У', lc)); break;
					case 'F': sb.append(ch('Ф', lc)); break;
					case 'C': sb.append(ch('Ц', lc)); break;
					default: sb.append(ch(ch, lc));
				}
			}

			i++; // переходим к следующему символу
		}
		return sb.toString();
	}

	public static String cyr2lat(char ch){
		switch (ch){
			case 'А': return "A";
			case 'Б': return "B";
			case 'В': return "V";
			case 'Г': return "G";
			case 'Д': return "D";
			case 'Е': return "E";
			case 'Ё': return "JO";
			case 'Ж': return "ZH";
			case 'З': return "Z";
			case 'И': return "I";
			case 'Й': return "Y";
			case 'К': return "K";
			case 'Л': return "L";
			case 'М': return "M";
			case 'Н': return "N";
			case 'О': return "O";
			case 'П': return "P";
			case 'Р': return "R";
			case 'С': return "S";
			case 'Т': return "T";
			case 'У': return "U";
			case 'Ф': return "F";
			case 'Х': return "KH";
			case 'Ц': return "C";
			case 'Ч': return "CH";
			case 'Ш': return "SH";
			case 'Щ': return "SHH";
			case 'Ъ': return "JHH";
			case 'Ы': return "IH";
			case 'Ь': return "JH";
			case 'Э': return "EH";
			case 'Ю': return "JU";
			case 'Я': return "JA";
			default: return String.valueOf(ch);
		}
	}

	public static String cyr2lat(String s){
		StringBuilder sb = new StringBuilder(s.length()*2);
		for(char ch: s.toCharArray()){
			char upCh = toUpperCase(ch);
			String lat = cyr2lat(upCh);
			if(ch != upCh){
				lat = lat.toLowerCase();
			}
			sb.append(lat);
		}
		return sb.toString();
	}

	/**
	 * Вспомогательная функция для восстановления регистра
	 */
	private static char ch(char ch, boolean toLowerCase){
		return toLowerCase? Character.toLowerCase(ch): ch;
	}

	/**
	 * Пробы
	 */
	public static void main(String[] args) {
		String s1 = cyr2lat("Александр Иванович Лебедь");
		String s2 = cyr2lat("Веснушчатый Щавелевый");
		String s3 = cyr2lat("Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства");
		String s4 = cyr2lat("Съешь же ещё этих мягких французских булок да выпей чаю.");
		String s5 = cyr2lat("А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я");

		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s3);
		System.out.println(s4);
		System.out.println(s5);
		System.out.println();
		System.out.println(lat2cyr(s1));
		System.out.println(lat2cyr(s2));
		System.out.println(lat2cyr(s3));
		System.out.println(lat2cyr(s4));
		System.out.println(lat2cyr(s5));
	}
}

Код приведен только для экспериментов и наглядного описания алгоритма обратного преобразования.

Для промышленных нужд транслитерации есть соответствующие решения (хотя готового решения по требованиям 1 и 2 нет).
Из промышленных стандартов транслитерация входит в Unicode Common Locale Data Repository Project (CLDR).
Есть очень мощная реализация в том числе CLDR: International Components for Unicode.
Конкретно Java-версия ICU: ICU4J.
Там есть фреймворк для описания и выполнения транслитерации (и много чего еще).
Для российской кириллицы там есть готовые реализации:
1. ISO 9. Обратимая, но с диакритами.
2. BGN. Без диакритов, но с пунктуационными знаками и необратимая.
Есть «неопределенный план» добавить ГОСТ.
Если будет время и силы разобраться, сделаю и выложу реализацию своей схемы средствами ICU4J.


Благодаря конструктивной критике в комментариях, решение изменилось. Моё понимание проблемы стало глубже. Задумался о «взрослой» реализации.
Всем спасибо! Хабр делает вещи лучше.

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


  1. silencer
    26.08.2015 12:08
    +16

    <sarcasm>
    <img src="комикс_про_еще_один_стандарт.png">
    </sarcasm>


    1. Krypt
      26.08.2015 12:30
      +1

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


      1. silencer
        26.08.2015 12:37

        За обратимость автору спасибо. Но все-таки еще один стандарт — это не очень хорошо.

        Может просто это только меня задолбало, но… Во всех трех загранпаспортах, которые у меня были, три разных варианта транслитерации имени. На банковских картах — вариантов 5 видел (когда-то в анкете на выпуск карты не спрашивали как правильно транслитерировать). И это при не самом сложном имени и фамилии. Хорошо еще, что в паспорте в фамилии вместо «ё» написано «е» — иначе боюсь представить сколько разных вариантов было бы.


        1. nickolaym
          26.08.2015 12:41
          +4

          Ха, пять вариантов на банковских картах. Мне в одном банке в один день выпустили две карты (дебетовую и кредитную) с разной транслитерацией. Алгоритм-шмалгоритм. Кривые руки любой алгоритм уделают.


      1. ploop
        26.08.2015 21:46

        Даже используемая для пластиковых карт не однозначна при обратном преобразовании.

        У меня 3 карты, и на всех трёх имя (Юрий) написано по разному :)


        1. Firsto
          27.08.2015 09:54

          У меня тоже "-ий" в фамилии по-разному на трёх разных картах.


          1. tendium
            27.08.2015 11:24

            Достаточно показать загран и попросить написании в соответствии с ним. В свою очередь в загране можно сохранять старое написание даже при смене стандарта (сейчас стандарт новый, но написание у меня сохранили старого).


            1. Mrrl
              27.08.2015 11:48

              Чтобы сохранить старое написание, нужна уважительная причина. Желательно, такая, за которую не расстреляют на месте.


              1. silencer
                27.08.2015 11:52

                Достаточно того, что есть другие документы имя в которых записано в соответствии со старым загранпаспортом.


                1. Mrrl
                  27.08.2015 12:01

                  Например? Кредитную карточку заграничного банка не предлагать (если нет разрешения ЦБ).


                  1. silencer
                    27.08.2015 12:04

                    Водительские права, любая кредитка.
                    Возможно потребуется написать заявление на имя начальника отделения, но это уже зависит от того, насколько сильно развит «синдром вахтера» у работников этого отделения.


                    1. Mrrl
                      27.08.2015 12:09

                      Водительские права? В смысле, международные? Представляется более вероятным, что их предложат поменять — в конце концов, это всего лишь перевод российских прав.
                      У меня в своё время сработало «наличие действующей визы». Заявление, конечно, писать пришлось.


              1. tendium
                27.08.2015 12:44

                Смотрим:

                17.10. Письменное заявление об изменении написания в паспорте фамилии и/или имени гражданина, которому оформляется паспорт, буквами латинского алфавита, составленное в произвольной форме, в котором указана причина, являющаяся основанием для изменения написания фамилии и/или имени, с приложением одного из следующих подтверждающих документов и его копии: ранее выданного паспорта, свидетельства о рождении, свидетельства о заключении (расторжении) брака, свидетельства о перемене имени, вида на жительство — в случае, если заявитель желает изменить порядок упомянутого написания, предусмотренный абзацами 2 и 4 подпункта 43.4 пункта 43 настоящего Регламента.


                Обратите внимание на пункт ранее выданного паспорта.

                P.S. В моем случае было еще проще: у меня в момент обмена паспорта был действующий ВНЖ другого государства, где фамилия была указана в соответствии с написанием в старом паспорте.


                1. Mrrl
                  27.08.2015 12:52

                  Обратите внимание на пункт ранее выданного паспорта

                  Копия паспорта — это хорошо. Но причину-то какую писать?


                  1. tendium
                    27.08.2015 14:28

                    Причина, например, зарегистрированное доменное имя на старое написание и использование его для общения с зарубежными коллегами. Использование на визитках старого написания, и известность вас лично людям именно по старой транскрипции. Регистрация программных продуктов, купленных за рубежом на ваше имя в старой транскрипции, и невозможность поменять имя в лицензии без повторной покупки. Еще вы, например, можете сказать, что подали заявление на долгосрочную визу в другое государство (паспорт в таком случае не забирают), и смена написания создаст вам проблемы с вклейкой этой самой визы. Еще это могут быть разные варианты написания фамилии у детей (если есть) и вас — может оказаться существенным аргументом. Это то, что мне навскидку пришло в голову. Я уверен, что вы можете придумать и другие не менее уважительные причины.


      1. ComodoHacker
        26.08.2015 22:57

        Первая обратимая? Вы с ISO 9/ГОСТ 7.79 не знакомы?


      1. bolk
        27.08.2015 20:18

        Обратимый транслит используется в WackoWiki, например.


        1. Vladimir_Zaitsev
          27.08.2015 21:21

          Про WackoWiki уже писали. Я нашел исходник, это оно?


    1. Vladimir_Zaitsev
      26.08.2015 14:17

      С удовольствием использовал бы стандарт, а еще лучше — готовое решение. Но обратимых не нашел, пришлось городить огород.


      1. Vapaamies
        26.08.2015 14:54

        Обратимый транслит разрабатывался в WackoWiki, там же была реализация.


        1. Vladimir_Zaitsev
          26.08.2015 15:47

          Вы это имеете в виду?
          Там вроде и «ь» и «ъ» заменяются на "_", так что с обратимостью будут проблемы.


      1. silencer
        26.08.2015 15:20

        А так ли нужна обратимость в вашем конкретном случае? Как я понимаю, в клинике должна быть БД пациентов с именами/фамилиями — почему бы не использовать ее для обратной транслитерации? В смысле перебрать все возможные варианты обратной транслитерации и проверить не встречается ли такое имя/фамилия в БД.

        Кстати, а не может ли быть такой ситуации, что результат/распечатка томограммы может потребоваться пациенту для передачи его (этого ответа) в зарубежную клинику? В этом случае, опять же, лучше использовать стандарт транслитерации для загранпаспортов.


        1. Vladimir_Zaitsev
          26.08.2015 15:57

          Согласен, как-то можно было выкрутится.
          Но с обратимой транслитерацией все намного проще:
          — можно заполнить документы по-русски вручную, если нет доступа к системе (бывает такое);
          — можно сделать автономную утилиту по генерации документов из данных исследования без связи с базой;
          — можно искать в базе ФИО не боясь, что найдутся разные варианты.
          С зарубежной клиникой да, поэтому и старались сделать по-возможности читаемый вариант. Но точное совпадение с загранпаспортом никому не нужно. Тем более что в загранпаспортах используют разные схемы транслитерации, они сами с собой не совпадают.


      1. ComodoHacker
        26.08.2015 22:57

        Как насчет ISO 9/ГОСТ 7.79?


        1. encyclopedist
          26.08.2015 23:22

          Использует апострофы (в варианте Б). Автору, как я понял, это не подходило.


  1. Krypt
    26.08.2015 12:36
    +8

    > Shheshjh
    «Шшешйх… Шхешйх… А, съешйх!»

    Очень неудачное сочетание символов.


    1. Krypt
      26.08.2015 12:41
      +4

      Я бы на вашем месте всё таки отказался от сочетаний hh и jh. Возможно всё таки в пользу применения апострофа.
      hh и jh выглядят слишком синтетическими, а учитывая, что «h» — это суффикс — распознавание сочетания человеком сильно усложняется.

      Как вариант:
      Ъ — '
      Ь — j'


      1. Goodkat
        26.08.2015 12:57

        Тогда уж:
        ь — '
        ъ — "

        Правда, не сработает, если в имени будет апостроф.
        У нас работает человек с апострофом в фамилии — до этого я и не знал, что такое бывает. Фамилия иностранная, правда.



        1. tendium
          26.08.2015 13:07

          В чешском языке, например, апостроф может быть частью буквы: t, d (может в зависимости от шрифта отображаться как апостроф, или реже как «галочка» типа как в буквах e или n). Так что не такая уж большая проблема.


        1. Krypt
          26.08.2015 13:08

          Кавычки — нельзя, потому как они могут присутствовать в оригинальной строке. Собственно, как и апостроф, но в русском языке он крайне редкий гость.

          Впрочем, для апострофа можно так же символ ввести… 'h Или 'h использовать для твёрдого знака


      1. Vladimir_Zaitsev
        26.08.2015 14:21
        +1

        Хорошо бы, но использовать знаки препинания нельзя было по требованию — унаследованная система их не принимает. Использование в результате только букв латиницы — один из основных плюсов этого решения.


    1. Vladimir_Zaitsev
      26.08.2015 14:19

      Да, в основном из-за «HH».


  1. nickolaym
    26.08.2015 12:40
    +5

    Самый тяжёлый случай — это слова «зъъъъъъ» и «жъъъъъъ» :)) — «zhhhhhhhhhhhh» и «zhhhhhhhhhhhhh» соответственно.
    То есть, смотреть вперёд надо не на 3 буквы, а на чётность-нечётность.
    И мы внезапно из регулярной грамматики попадаем в контекстно-свободную.
    Пусть и очень простенькую, на одном изолированном случае (ъъ не встречается в обычной русской орфографии), и легко разбираемую даже перл-совместимыми регекспами (которые вообще являются подклассом контекстно-зависимых).


    1. Zibx
      26.08.2015 12:48
      +2

      Скрытый текст
      image


    1. Vladimir_Zaitsev
      26.08.2015 14:27

      Спасибо за наглядный пример.
      Понятно, «HH» — решение не удачное.
      На будущее можно подумать, как это лучше сделать.
      Пока только «JHH» в голову приходит. Это сделает грамматику регулярной, упростит считывание человеком, и, похоже, освободит «SHH» для «Щ».


      1. nickolaym
        26.08.2015 14:53
        +3

        Глядя на эти буквосочетания, постоянно вспоминаю древнее JHWH (без гласных можно, Б-г простит) и современное JWH (без цифр можно, ГНК простит).


        1. Vladimir_Zaitsev
          26.08.2015 16:25

          Меня в последнем регулярно коллеги подозревают, просят отсыпать. А у меня нет.


  1. WeslomPo
    26.08.2015 12:55
    +2

    Если я не ошибаюсь, у вас осталось еще два символа X, W которые можно было спокойной использовать, один для ШЩ другой ЬЪ например так W, JW, X, JX. Потому что «Shheshjh» — «Sjxeswx». «Сджиксесв» — вы даже не попытаетесь прочесть потому что бред, поэтому доходит быстрее чем «Сххешджх». Несмотря на фонетическую дикость.

    Или хотя бы «Sxxeshx». А для Щ — JH.


    1. Krypt
      26.08.2015 12:58

      Зато как «Сжхесив» — пожалуйста. В определённый момент мозг бунтует и отказывается воспринимать символы.
      Тут это даже сильнее выражено, чем в оригинале.


    1. Killy
      26.08.2015 13:51

      > Sxxeshx
      Прикольно. Это легче всего читается. «x» легко пропускается при чтении как беззвучный символ, пауза.


    1. Vladimir_Zaitsev
      26.08.2015 14:47

      Да, не использованы символы «Q», «X», «W». Не использованы сознательно. Проблема с ними в том, что у них есть вполне определенное звучание в любом языке. Даже «J» для людей — проблема, с трудом привыкают не «озвучивать» букву при чтении.


  1. OLS
    26.08.2015 13:05

    С целью значительного облегчения алгоритма обращения я бы предложил

    Щ — TH
    Ъ — JH либо JJ
    Ь — JY


    1. Vladimir_Zaitsev
      26.08.2015 14:55

      Предложение интересное. Было бы хорошо ограничится двух-буквенными кодами.
      Про «TH» для «Щ» думал, но это сочетание всем известно, и читается совсем не как «Щ». Людям будет трудно «переключаться».
      «JJ» — плохое сочетание, по тем же причинам, что и «HH» — приводит к нарушению однозначности. Выше есть комментарии с теорией.
      «Ь» --> «JY» возможно, но противоречит принципу «для букв, которым не соответствуют звуки, нельзя использовать буквы, для которых звуки есть».


      1. tyomitch
        28.08.2015 08:59

        Про «TH» для «Щ» думал, но это сочетание всем известно, и читается совсем не как «Щ».

        Интересно, что на эту тему скажет Мищгол?


      1. OLS
        28.08.2015 12:36

        «JJ» — плохое сочетание, по тем же причинам, что и «HH» — приводит к нарушению однозначности. Выше есть комментарии с теорией


        Поясните, пожалуйста, в каких случаях это приводит к нарушению однозначности?


        1. Vladimir_Zaitsev
          28.08.2015 14:35

          Имел в виду, сочетания типа «JJJJJJJJJJJJA» --> «ЪЪЪЪЪЪА», «JJJJJJJJJJJJJA» --> «ЪЪЪЪЪЪЯ», «JJJJJJJJJJJJJB» --> ошибка.
          По аналогии с комментарием nickolaym.
          Сейчас вижу, что выразился неверно. Обратное преобразование остается однозначным, просто алгоритм будет сложнее.

          Понимаю, что случай нескольких твердых знаков подряд для русского языка не характерен, но входному контракту не противоречит, и лучше бы, чтобы алгоритм на нем не ломался.
          В общем, если коды будут образовывать регулярную грамматику, все будет изящнее.


          1. nickolaym
            28.08.2015 15:09

            Алгоритм не будет сложнее. В данном случае, с префиксами, грамматика осталась регулярной.
            Но для глаз это, конечно, ад.


            1. Vladimir_Zaitsev
              28.08.2015 16:03

              Ваша правда, грамматика осталась регулярной.
              Может, подскажите, как называется такое свойство: «если коды образуются с помощью префиксов и постфиксов, ни один код не должен начинаться с постфикса или заканчиваться префиксом»?


  1. ServPonomarev
    26.08.2015 13:16

    Один оригинальный способ транслитерации туда и обратно — это дистрибутивная семантика. Берёте корпус с сообщениями на транслите и на русском, обучаетесь и получается в итоге (отсюда):

    ./distance vectors.bin
    Enter word or sentence (EXIT to break): avito

    Word: avito Position in vocabulary: 1999

    Word Cosine distance
    — awito 0.693721
    авито 0.675299
    fvito 0.661414
    авита 0.659454
    irr 0.642429
    овито 0.606189
    аviто 0.598056

    ./distance vectors.bin
    Enter word or sentence (EXIT to break): пщщпду
    — пщщщпду 0.723194
    пщщпд 0.721070
    пщпд 0.712373
    пщппду 0.704579
    пщщаду 0.695897
    пщщпдк 0.694641
    пщпду 0.692646
    ппщду 0.681183
    пщщп 0.660203
    пгпд 0.653649
    гугл 0.649897
    поопду 0.647420
    ппщпду 0.643923
    пщщплу 0.641619
    нфтвуч 0.640587
    пщщпдуюкг 0.631423
    пщщпу 0.620105
    gogle 0.616396
    иштп 0.612234
    google 0.608240


    1. Vladimir_Zaitsev
      26.08.2015 14:59

      Действительно, оригинально.


  1. AxisPod
    26.08.2015 14:45
    +1

    Как бы есть даже стандарты ГОСТ, и у них всё нормально с обратимостью, зачем изобретать новое? Или даже в вики нельзя было посмотреть? https://goo.gl/qJLoCr


    1. encyclopedist
      26.08.2015 15:20

      Вы который из Гостов имеете ввиду? Они все либо необратимые, либо с диакритикой, насколько я могу судить по приведенной выми ссылке.


    1. Vladimir_Zaitsev
      26.08.2015 15:21

      Конечно, смотрел, и много куда еще. Вариант «ГОСТ 16876-71 / таблица 2» почти подходит, но все же использует знаки препинания для твердого и мягкого знаков. А не везде это допустимо. Например, та система, с которой мне надо было общаться, их не принимала.
      Ну, а раз все равно что-то менять, решил заодно исправить неудачные, на мой взгляд, решения («Ы», «Й», «Ё»). А «Щ» пришлось менять вынужденно, с радостью бы оставил как в ГОСТе.
      В остальном предложенное решение соответствует ГОСТ.


  1. dharma
    26.08.2015 15:17

    Успенский В. А. К проблеме транслитерации русских текстов латинскими буквами / Труды по НЕматематике. с. 390-412.
    http://gen.lib.rus.ec/book/index.php?md5=BD756272C0A86DB220B0A0BA581CA33B


    1. Vladimir_Zaitsev
      26.08.2015 16:14

      Спасибо за ссылку, познавательно.
      У меня стояла гораздо менее «академическая» задача.


  1. maaGames
    26.08.2015 15:31

    Что может быть очевиднее, чем использовать букву X(икс) для буквы Х(ха)?
    Скажете, «экс» звучит не как «хэ»? Ну так и U(йууу) звучит не как У(уууу)…

    Кстати, недавно решал проблему перевода из транслита в русский. Однозначного перевода не получилось, разумеется, но удалось реализовать поддержку нескольких внегласных стандартов транслитерального написания. Благо, они не взаимоисключающие в большинстве случаев. Например, буку «Ш» распознаю и как 'w' и как 'sh'. При этом 'shch' однозначно определяется как 'щ', потому что я не придумал в Русском языке слов со слогом «шч». С большинством других сложных букв аналогично получилось разобраться. Но вот мягкий/твёрдый знак, ё и ы доставляют проблемы, конечно. В первую очередь из-за того, что их при транслите или вообще не указывают или пишут «у». Т.е. без последующего прогона по словарю не обойтись.


    1. Vladimir_Zaitsev
      26.08.2015 16:22

      Тем не менее, ни один стандарт такой «графический» подход не использует. Разве только для номеров автомобилей. Вероятно, классические схемы транслитерации основаны не только и не столько на английской фонетике.

      Задача распознавания произвольного транслита интересна, да. Собственно, в статье описана попытка от такой задачи уйти.


      1. maaGames
        26.08.2015 16:42

        К сожалению, мне нужно было не придумать обратимую транслитеризацию, а обращать уже имеющуюся.
        Стандарты вообще тсранные. Вроде бы даже несколько ГОСТов есть, не говоря о прочих вариациях.
        Вот если бы появился не «ещё один стандарт»(с), а один единственный обратимый стандарт транслитеризации, который все соблюдают, то было бы няшно.


    1. michael_vostrikov
      26.08.2015 20:26
      +2

      «веснушчатый» )


      1. maaGames
        26.08.2015 20:28

        Вот взял и всё испортил.)
        Но неотличимость «ь»-«ъ» и «у»-«ы» в большинстве нотаций создаёт больше проблем, чем «веснушчатый».


    1. Mrrl
      26.08.2015 21:16

      При этом 'shch' однозначно определяется как 'щ', потому что я не придумал в Русском языке слов со слогом «шч»

      Довольно быстро находится слово «Машчермет». Правда, это имя собственное — название ж/д станции, да ещё и заграничной…


      1. maaGames
        27.08.2015 15:09

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


  1. bubuq
    26.08.2015 17:42
    +2

    V cёm korni vasej neprijazni k diakriticeskim znakam?


    1. Krypt
      26.08.2015 18:07
      +1

      Могу предположить, что в отсутствии их доступном кодовом диапазоне.


      1. bubuq
        27.08.2015 08:36

        В смысле, где-то жёстко требуется ASCII в наше время?


        1. Vladimir_Zaitsev
          27.08.2015 18:51

          Да, например в софте некоторых томографов.


  1. jar_ohty
    26.08.2015 18:11

    Слова «исход» и «Ицхак» не портятся — уже хорошо. Но вот англоориентированность в этом стандарте раздражает.


  1. FFormula
    26.08.2015 19:32
    +1

    Недавно изобретал тот же велосипед. Некоторые буквы латинского алфавита в разных транслитах так и остаются неиспользуемыми. Почему бы их не использовать вместо сочетаний HH, JH и т.д.

    Пояснения к сочетаниям.
    yo — ё, yu — ю, ya — я — Тут всё просто. Как в русском языке эти буквы раскладываются на сочетание звуков «й+о», «й+у», «й+а». Тут всё стандартно и понятно. А вот как быть в обратном случае? У нас есть «е», но нет «э». Есть «и», но нет «ы». Нужно наоборот убрать «й» из звучания. Для этого я использовал «w» — как символ убирающий «й» из звучания. «we» («е» без «й») — «э». «wi» — «ы».
    Сама по себе «w» отдельно как буква не используется, поэтому разночтений не бывает.
    Для «х» используется «x» (экс). Это даёт возможность убрать разночтения из сочетаний sh, ch, zh, так как «h» сама по себе не используется.

    А — A
    Б — B
    В — V
    Г — G
    Д — D
    Е — E
    Ё — Yo
    Ж — Zh
    З — Z
    И — I
    Й — Y
    К — K
    Л — L
    М — M
    Н — N
    О — O
    П — P
    Р — R
    С — S
    Т — T
    У — U
    Ф — F
    Х — X
    Ц — C
    Ч — Ch
    Ш — Sh
    Щ — Shh
    Ь — Q
    Ы — Wi
    Ъ — J
    Э — We
    Ю — Yu
    Я — Ya

    (комментарий пользователя http://habrahabr.ru/users/VasakaInc/)


  1. Mrrl
    26.08.2015 21:07

    Когда я сочинял такую штуку, то в качестве Й выбрал J, а для смягчения — Y. В остальном совпадало, за исключением:
    Щ — Shh
    Ь — X
    Ъ — Xh
    Ё — Yo (чтобы остался вариант для ?)
    І — Yi
    ? — Ye
    ? — Th
    ? — W
    Были ещё сочетания Gh и Uh. Сочетаний для букв Є и Ї не придумал (Ehh и Yyi ?).


  1. zelenin
    26.08.2015 21:19
    +1

    Просто плАчу.
    Есть cldr с реализациями на большинстве ЯП. Но все почему-то думают, что надо делать свой велосипед с маппингом букв, что изначально неуниверсально и нестандартизировано.


    1. Vladimir_Zaitsev
      27.08.2015 12:42

      Спасибо за наводку, проект интересный.
      По теме там нашел вот это: "Cyrillic generally follows ISO 9". То есть ничего неожиданного.
      А в реализации для Java транслитерации вроде нет.


      1. zelenin
        27.08.2015 12:57

        ICU4J is an add-on to the regular JRE that provides:
        Transforms – a flexible mechanism for Unicode text conversions
        Including Full/Halfwidth conversions, Normalization, Case conversions, Hex conversions, and transliterations between scripts (50+ pairs)

        Это не интересный проект, а стандарт де-факто.


        1. Vladimir_Zaitsev
          27.08.2015 16:15

          Извиняюсь, не туда посмотрел. Конечно, транслитерации есть и она полностью обратима.

          Если кому интересно, как пробовал:
          maven,
          Java:
          		Transliterator cyr2lat = Transliterator.getInstance("Cyrillic-Latin");
          		Transliterator lat2cyr = Transliterator.getInstance("Latin-Cyrillic");
          		String cyr = "НОЧЬ, ПОДЪЕЗД! ночь, подъезд?";
          		String lat = cyr2lat.transliterate(cyr);
          		String cyr_lat_cyr = lat2cyr.transliterate(lat);
          		System.out.println(cyr);
          		System.out.println(cyr.length());
          		System.out.println(lat);
          		System.out.println(lat.length());
          		System.out.println(cyr_lat_cyr);
          

          Выводит:
          НОЧЬ, ПОДЪЕЗД! ночь, подъезд?
          29
          NOC??, POD??EZD! noc?, pod?ezd?
          31
          НОЧЬ, ПОДЪЕЗД! ночь, подъезд?


          1. zelenin
            27.08.2015 17:28

            Какая-то каша) также как будете объяснить как пользоваться своим вариантом.
            (при транслите вы выбрали кириллицу, а надо было русский)


            1. Vladimir_Zaitsev
              27.08.2015 20:12

              Как я объяснял, я в статье написал. Три строчки правил, таблица (в основном всем знакомая). Памятка на пол-листа. Не сразу, конечно, но люди не из IT могут выполнять транслитерацию в уме (в обе стороны) и ввести результат с клавиатуры куда им надо.

              А ICU предлагает диакриты, да ещё составные. Их не все unicode системы поддерживают, не говоря о старых. И на клавиатуре их нет.

              Под русским Вы имели в виду «Ru-En»? Или «Ru-Latin»? Все четыре варианта приводят к одному транслитератору, просто по более длинным цепочкам.


              1. zelenin
                27.08.2015 20:19

                ICU ничего не предлагает — вы сами выбираете.
                Russian-Latin/BGN; Any-Latin; Latin-ASCII; NFD; [:Nonspacing Mark:] Remove; NFKC; — такой вариант транслитирирует русский в латиницу, денормализует, уберет лишнее и приведет с compatibility форме (например индексы приведет к обычным цифрам, а евро к Е).


                1. Vladimir_Zaitsev
                  27.08.2015 21:04

                  Да, «Russian-Latin/BGN» я не заметил, спасибо.
                  Но BNG же не обратима?
                  Они и сами так пишут: «Unicode CLDR provides other transliterations based on the U.S. Board on Geographic Names (BGN) transliterations. These are currently unidirectional — to Latin only.»
                  Она и в принципе не обратима («Ц» --> «TS»), и не чисто буквенная («ь» --> "'").
                  А фильтры — это хорошо, но здесь не помогает.


                  1. zelenin
                    27.08.2015 22:33

                    про обратимость я не говорил — это узкий кейс.


  1. bodqhrohro
    26.08.2015 21:45

    JSH
    Почему не JS, например? Или JC (аналогия по хвостику)? Третий символ тут никакой погоды не даёт — ни на обратимость не влияет, ни на читаемость этой псевдофонетической каши. Пожалуй, читаемость даже ухудшает.


  1. TimsTims
    27.08.2015 01:34
    -1

    JSH, HH, JH?
    А разве смысл транслитерации не в том, чтобы условно «любой» человек смог более-менее понятно и правильно прочитать и произнести слово?

    Ну вот слово, которое вам нужно по-быстрому прочитать:
    Щавелевый

    Получается как:
    Jshavelevihy
    йшавелевихы — так прочтет обычный человек по привычке читающий латиницу.

    Раз уж вы решили изобретать свой велосипед с двойными HH JSH итд, то раз уж всё-равно всем вашим работникам придется зазубривать новую кодировку букв, то не проще было сразу придумать какой-нибудь цифровой код? Ну допустим X1 X2 X3 X4 итд. учить надо меньше и глаза не пытаются произносить буквы так, как всех учили в школе, ломая прошлую выучку.
    А представьте, что будет, когда человек, запомнивший все ваши «стандарты» вдруг решит написать кому-то сообщение, находясь за границей, используя транскрипцию? Он по новой памяти начнет набирать HH JSH итд. И кто его тогда поймет? Думаю только его коллега..)


    1. Vladimir_Zaitsev
      27.08.2015 21:53

      Так я же признаю, что вариант не идеальный.
      Кстати вопрос, почему «обычный человек» читает «y» как «ы»? Какой язык надо было в школе учить для этого?
      Да и «Helen» читается вроде как «Элен». Откуда «х»?
      По поводу «X1 X2» — это сарказм, да?
      Хотелось как раз минимально испортить ГОСТ, но добиться обратимости.
      А «привычная» транслитерация, к сожалению, у всех разная.


      1. Mrrl
        27.08.2015 22:00

        Samaq priwy~naq transliteraciq pri{la e}e iz KOI-8. Ostalxnoe — nowomodnye izobreteniq.
        (dA, NADO BYLO E]E POMENQTX REGISTRY)


  1. petropavel
    27.08.2015 11:11

    Когда-то давно я преобразовывал транслитерацию в кириллицу статистически. Посчитал вероятности переходов между буквами на корпусе русских текстов. Ну и для каждого слова в транслите считал все возможные варианты в кириллице и их вероятности. Побеждал наиболее вероятный вариант. Получалось не без ошибок (лень было словарь прикручивать) но вполне читабельно. Работало, естественно, на любом транслите — собеседники даже не знали, что все их сообщения так обрабатываются, писали как хотели, там никаких формализуемых правил вообще не было и близко.


  1. KvanTTT
    27.08.2015 11:50

    каждую исходную букву преобразовывать независимо от остальных (без сложностей вроде «в начале / в конце слова» и т.п.)

    Ну, кстати, для человека это может быть наоборот удобней, но сложнее для обработки (возможно понадобится уже КС грамматика).


  1. hard_sign
    27.08.2015 15:35

    Вспоминается байка про то, как в техпаспорте было написано «Хонда Цивик», а при оформлении Зелёной карты в полис вписали «Tsivik» :)