package api import ( "bytes" ) // ////////////////////////////////////////////////////////////////////////////////// // type specProc func(p, c, n rune, extMap map[string]string) (string, bool) // ////////////////////////////////////////////////////////////////////////////////// // var baseRuEn = map[string]string{ "а": "a", "А": "A", "Б": "B", "б": "b", "В": "V", "в": "v", "Г": "G", "г": "g", "Д": "D", "д": "d", "З": "Z", "з": "z", "И": "I", "и": "i", "К": "K", "к": "k", "Л": "L", "л": "l", "М": "M", "м": "m", "Н": "N", "н": "n", "О": "O", "о": "o", "П": "P", "п": "p", "Р": "R", "р": "r", "С": "S", "с": "s", "Т": "T", "т": "t", "У": "U", "у": "u", "Ф": "F", "ф": "f", } var scientificRuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "Ë", "ё": "ë", "Ж": "Ž", "ж": "ž", "Й": "J", "й": "j", "Х": "Ch", "х": "ch", "Ц": "C", "ц": "c", "Ч": "Č", "ч": "č", "Ш": "Š", "ш": "š", "Щ": "Šč", "щ": "šč", "Ъ": "″", "ъ": "″", "Ы": "Y", "ы": "y", "Ь": "′", "ь": "′", "Э": "È", "э": "è", "Ю": "Ju", "ю": "ju", "Я": "Ja", "я": "ja", } var iso9ARuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "Ë", "ё": "ë", "Ж": "Ž", "ж": "ž", "Й": "J", "й": "j", "Х": "H", "х": "h", "Ц": "C", "ц": "c", "Ч": "Č", "ч": "č", "Ш": "Š", "ш": "š", "Щ": "Ŝ", "щ": "ŝ", "Ъ": "″", "ъ": "″", "Ы": "Y", "ы": "y", "Ь": "′", "ь": "′", "Э": "È", "э": "è", "Ю": "Û", "ю": "û", "Я": "Â", "я": "â", } var iso9BRuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "Yo", "ё": "yo", "Ж": "Zh", "ж": "zh", "Й": "J", "й": "j", "Х": "X", "х": "x", "Ч": "Ch", "ч": "ch", "Ш": "Sh", "ш": "sh", "Щ": "Shh", "щ": "shh", "Ъ": "``", "ъ": "``", "Ы": "Y`", "ы": "y`", "Ь": "`", "ь": "`", "Э": "E`", "э": "e`", "Ю": "Yu", "ю": "yu", "Я": "Ya", "я": "ya", } var isoR91RuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "Ë", "ё": "ë", "Ж": "Ž", "ж": "ž", "Й": "J", "й": "j", "Х": "H", "х": "h", "Ц": "C", "ц": "c", "Ч": "Č", "ч": "č", "Ш": "Š", "ш": "š", "Щ": "Ŝ", "щ": "ŝ", "Ъ": "″", "ъ": "″", "Ы": "Y", "ы": "y", "Ь": "′", "ь": "′", "Э": "È", "э": "è", "Ю": "Û", "ю": "û", "Я": "Â", "я": "â", } var isoR92RuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "Jo", "ё": "jo", "Ж": "Zh", "ж": "zh", "Й": "Jj", "й": "jj", "Х": "Kh", "х": "kh", "Ц": "C", "ц": "c", "Ч": "Ch", "ч": "ch", "Ш": "Sh", "ш": "sh", "Щ": "Shh", "щ": "shh", "Ъ": "″", "ъ": "″", "Ы": "Y", "ы": "y", "Ь": "′", "ь": "′", "Э": "Eh", "э": "eh", "Ю": "Ju", "ю": "ju", "Я": "Ja", "я": "ja", } var bgnRuEn = map[string]string{ "Ж": "Zh", "ж": "zh", "И": "I", "и": "i", "Й": "Y", "й": "y", "Х": "Kh", "х": "kh", "Ц": "Ts", "ц": "ts", "Ч": "Ch", "ч": "ch", "Ш": "Sh", "ш": "sh", "Щ": "Shch", "щ": "shch", "Ъ": "″", "ъ": "″", "Ы": "Y", "ы": "y", "Ь": "′", "ь": "′", "Э": "E", "э": "e", "Ю": "Yu", "ю": "yu", "Я": "Ya", "я": "ya", } var bsRuEn = map[string]string{ "Е": "e", "е": "e", "Ё": "ë", "ё": "ë", "Ж": "zh", "ж": "zh", "Й": "ĭ", "й": "ĭ", "Х": "kh", "х": "kh", "Ц": "ts", "ц": "ts", "Ч": "ch", "ч": "ch", "Ш": "sh", "ш": "sh", "Щ": "shch", "щ": "shch", "Ъ": "″", "ъ": "″", "Ы": "ȳ", "ы": "ȳ", "Ь": "′", "ь": "′", "Э": "é", "э": "é", "Ю": "yu", "ю": "yu", "Я": "ya", "я": "ya", } var alalcRuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "Ë", "ё": "ë", "Ж": "Zh", "ж": "zh", "Й": "Ĭ", "й": "ĭ", "Х": "Kh", "х": "kh", "Ц": "T͡s", "ц": "t͡s", "Ч": "Ch", "ч": "ch", "Ш": "Sh", "ш": "sh", "Щ": "Shch", "щ": "shch", "Ъ": "″", "ъ": "″", "Ы": "Y", "ы": "y", "Ь": "′", "ь": "′", "Э": "Ė", "э": "ė", "Ю": "I͡u", "ю": "i͡u", "Я": "I͡a", "я": "i͡a", } var icaoRuEn = map[string]string{ "Е": "E", "е": "e", "Ё": "E", "ё": "e", "Ж": "Zh", "ж": "zh", "Й": "I", "й": "i", "Х": "Kh", "х": "kh", "Ц": "Ts", "ц": "ts", "Ч": "Ch", "ч": "ch", "Ш": "Sh", "ш": "sh", "Щ": "Shch", "щ": "shch", "Ъ": "Ie", "ъ": "ie", "Ы": "Y", "ы": "y", "Ь": "", "ь": "", "Э": "E", "э": "e", "Ю": "Iu", "ю": "iu", "Я": "Ia", "я": "ia", } var iso9BSpeical = map[string]string{ "ц": "cz", "Ц": "Cz", "ц+": "с", "Ц+": "С", } var bgnSpecial = map[string]string{ "е": "e", "Е": "E", "ё": "ë", "Ё": "Ë", "е+": "ye", "Е+": "Ye", "ё+": "yë", "Ё+": "Yë", } // ////////////////////////////////////////////////////////////////////////////////// // // EncodeToScientific encodes text with scientific mappings func EncodeToScientific(text string) string { return encode(text, scientificRuEn, nil) } // EncodeToISO9A encodes text with ISO 9:1995/A ГОСТ 7.79-2000/A mappings func EncodeToISO9A(text string) string { return encode(text, iso9ARuEn, nil) } // EncodeToISO9B encodes text with ISO 9:1995/B ГОСТ 7.79-2000/Б mappings func EncodeToISO9B(text string) string { return encode(text, iso9BRuEn, iso9BSpec) } // EncodeToBGN encodes text with BGN mappings func EncodeToBGN(text string) string { return encode(text, bgnRuEn, bgnSpec) } // EncodeToPCGN encodes text with PCGN mappings func EncodeToPCGN(text string) string { return encode(text, bgnRuEn, bgnSpec) } // EncodeToALALC encodes text with ALA-LC mappings func EncodeToALALC(text string) string { return encode(text, alalcRuEn, nil) } // EncodeToBS encodes text with BS 2979:1958 mappings func EncodeToBS(text string) string { return encode(text, alalcRuEn, nil) } // EncodeToICAO encodes text with ICAO mappings func EncodeToICAO(text string) string { return encode(text, icaoRuEn, nil) } // ////////////////////////////////////////////////////////////////////////////////// // func encode(text string, extMap map[string]string, proc specProc) string { if text == "" { return "" } var input = bytes.NewBufferString(text) var output = bytes.NewBuffer(nil) // Previous, next letter for special processor var p, n rune var rr string var ok bool for { r, _, err := input.ReadRune() if err != nil { break } if !isRussianChar(r) { output.WriteRune(r) p = r continue } if proc != nil { n, _, _ = input.ReadRune() input.UnreadRune() rr, ok = proc(p, r, n, extMap) if ok { output.WriteString(rr) continue } } p = r rr, ok = baseRuEn[string(r)] if ok { output.WriteString(rr) continue } rr, ok = extMap[string(r)] if ok { output.WriteString(rr) } } return output.String() } func iso9BSpec(p, c, n rune, extMap map[string]string) (string, bool) { if c != 'ц' && c != 'Ц' { return "", false } rr, ok := baseRuEn[string(n)] if !ok { rr = extMap[string(n)] } switch rr { case "e", "i", "y", "j", "E", "I", "Y", "J": return iso9BSpeical[string(c)+"+"], true } return iso9BSpeical[string(c)], true } func bgnSpec(p, c, n rune, extMap map[string]string) (string, bool) { switch c { case 'е', 'Е', 'ё', 'Ё': // nop default: return "", false } switch p { case 0, ' ', 'а', 'у', 'о', 'ы', 'и', 'э', 'я', 'ю', 'А', 'У', 'О', 'Ы', 'И', 'Э', 'Я', 'Ю': return bgnSpecial[string(c)+"+"], true } return bgnSpecial[string(c)], true } func isRussianChar(r rune) bool { switch { case r >= 1040 && r <= 1103, r == 1105, r == 1025: return true } return false }