Алгоритм преобразования интернационального домена
Имеющаяся доменная система позволяет использовать весьма ограниченный набор символов в доменных именах — 26 латинских букв и несколько дополнительных знаков. По этой причине международные названия доменов пришлось ввести алгоритм, который однозначно преобразует цепь знаков Уникода в цепь знаков, доступных для использования в доменных именах, и наоборот. Таким алгоритмом стал алгоритм, называемый «Punycode». Для того, чтобы программа могла отличить доменное имя, которое нужно представить как международное (цепь знаков в Уникоде), от остальных, к результату преобразования имени домена по упомянутому алгоритму добавляется префикс «xn--».
Пример реализацииПравить
Ниже приведён пример реализации этого алгоритма на языке Глагол.
ОТДЕЛ Punycode; ИСПОЛЬЗУЕТ Асм ИЗ "...\Отделы\Иное\", Цепь ИЗ "...\Отделы\Иное\", Буква ИЗ "...\Отделы\Иное\", Вывод ИЗ "...\Отделы\Обмен\"; ЗАДАЧА РаскодРазр(c: ЦЕЛ): ЦЕЛ; УКАЗ ЕСЛИ c - 48 < 10 ТО ВОЗВРАТ c - 22 АЕСЛИ c - 65 < 26 ТО ВОЗВРАТ c - 65 АЕСЛИ c - 97 < 26 ТО ВОЗВРАТ c - 97 ИНАЧЕ ВОЗВРАТ 36 КОН КОН РаскодРазр; ЗАДАЧА ЗакодРазр(d: ЦЕЛ; f: КЛЮЧ): ЦЕЛ; УКАЗ ЕСЛИ d < 26 ТО ЕСЛИ f ТО ВОЗВРАТ d + 65 ИНАЧЕ ВОЗВРАТ d + 97 КОН ИНАЧЕ ЕСЛИ f ТО ВОЗВРАТ d - 10 ИНАЧЕ ВОЗВРАТ d + 22 КОН КОН КОН ЗакодРазр; ЗАДАЧА Адапт(д, н: ЦЕЛ; п: КЛЮЧ): ЦЕЛ; ПЕР сч: ЦЕЛ; УКАЗ ЕСЛИ п ТО д := УЗК(ВШИРЦЕЛ(ЦЕЛЧАСТЬ(д / 700))) ИНАЧЕ д := Асм.Сдвиг(д, -1) КОН; УВЕЛИЧИТЬ(д, УЗК(ВШИРЦЕЛ(ЦЕЛЧАСТЬ(д / н)))); сч := 0; ПОКА д > Асм.Сдвиг(((36 - 1) * 26), -1) ВЫП д := УЗК(ВШИРЦЕЛ(ЦЕЛЧАСТЬ(д / ( 36 - 1 )))); УВЕЛИЧИТЬ(сч, 36) КОН; ВОЗВРАТ УЗК(ВШИРЦЕЛ(ЦЕЛЧАСТЬ(сч + (36 - 1 + 1) * д / (д + 38)))) КОН Адапт; ЗАДАЧА ЗакодОсн(b: ЦЕЛ; f: КЛЮЧ): ЦЕЛ; УКАЗ ЕСЛИ b - 97 < 26 ТО УМЕНЬШИТЬ(b, 32) КОН; ЕСЛИ НЕ f И (b - 65 < 26) ТО ВОЗВРАТ b + 32 ИНАЧЕ ВОЗВРАТ b КОН КОН ЗакодОсн; ЗАДАЧА Закодировать-(вход-, выход+: РЯД ИЗ ЗНАК; учРег: КЛЮЧ); ПЕР входС: ДОСТУП К РЯД ИЗ ЗНАК; n, d, h, b, a, j, m, q, k, t, i, сч: ЦЕЛ; регБукв: ДОСТУП К РЯД ИЗ КЛЮЧ; длинаВхода, размерВыхода: ЦЕЛ; ЗАДАЧА ДобавитьЗнак(знак: ЗНАК): КЛЮЧ; УКАЗ ЕСЛИ сч >= размерВыхода ТО Вывод.Цепь("Память для результата слишком мала."); ВОЗВРАТ ОТКЛ КОН; выход[сч] := знак; УВЕЛИЧИТЬ(сч); ВОЗВРАТ ВКЛ КОН ДобавитьЗнак; УКАЗ ОБНУЛИТЬ(выход); длинаВхода := ДЛИНА(вход); СОЗДАТЬ(регБукв, длинаВхода); СОЗДАТЬ(входС, вход); Цепь.ВСтрочные(входС^); ЕСЛИ учРег ТО ОТ j := 0 ДО длинаВхода-1 ВЫП регБукв[j] := входС[j] # вход[j] КОН КОН; размерВыхода := РАЗМЕР(выход); сч := 0; n := 80H; d := 0; a := 72; ОТ j := 0 ДО длинаВхода-1 ВЫП ЕСЛИ ВЦЕЛ(входС[j]) < 80H ТО ЕСЛИ учРег ТО ЕСЛИ НЕ ДобавитьЗнак(ВЗНАК(ЗакодОсн(ВЦЕЛ(входС[j]), регБукв[j]))) ТО ВОЗВРАТ КОН ИНАЧЕ ЕСЛИ НЕ ДобавитьЗнак(входС[j]) ТО ВОЗВРАТ КОН КОН КОН КОН; b := ДЛИНА(выход); h := b; ЕСЛИ b > 0 ТО ЕСЛИ НЕ ДобавитьЗнак(2DX) ТО ВОЗВРАТ КОН КОН; ПОКА h < длинаВхода ВЫП m := МАКС(ЦЕЛ); ОТ j := 0 ДО длинаВхода-1 ВЫП i := ВЦЕЛ(входС[j]); ЕСЛИ (i >= n) И (i < m) ТО m := i КОН КОН; ЕСЛИ (m - n > ЦЕЛЧАСТЬ((МАКС(ЦЕЛ) - d) / (h + 1))) ТО Вывод.Цепь("Переполнение."); ВОЗВРАТ КОН; УВЕЛИЧИТЬ(d, (m - n) * (h + 1)); n := m; ОТ j := 0 ДО длинаВхода-1 ВЫП i := ВЦЕЛ(входС[j]); ЕСЛИ i < n ТО УВЕЛИЧИТЬ(d); ЕСЛИ d > МАКС(ЦЕЛ) ТО Вывод.Цепь("Переполнение."); ВОЗВРАТ КОН КОН; ЕСЛИ i = n ТО q := d; k := 36; КОЛЬЦО ЕСЛИ k <= a ТО t := 1 АЕСЛИ k >= a + 26 ТО t := 26 ИНАЧЕ t := k - a КОН; ЕСЛИ q < t ТО ВЫХОД КОН; ЕСЛИ НЕ ДобавитьЗнак(ВЗНАК(ЗакодРазр(t + (q - t) ОСТАТОК (36 - t), ОТКЛ))) ТО ВОЗВРАТ КОН; q := УЗК(ВШИРЦЕЛ(ЦЕЛЧАСТЬ((q - t) / (36 - t)))); УВЕЛИЧИТЬ(k, 36) КОН; ЕСЛИ НЕ ДобавитьЗнак(ВЗНАК(ЗакодРазр(q, учРег И регБукв[j]))) ТО ВОЗВРАТ КОН; a := Адапт(d, h + 1, h = b); d := 0; УВЕЛИЧИТЬ(h) КОН КОН; УВЕЛИЧИТЬ(d); УВЕЛИЧИТЬ(n) КОН КОН Закодировать; ЗАДАЧА Раскодировать-(вход-, выход+: РЯД ИЗ ЗНАК; учРег: КЛЮЧ); ПЕР сч, дл, длинаВхода, размерВыхода, r, i, j, n, w, k, t, b, o: ЦЕЛ; регБукв: ДОСТУП К РЯД ИЗ КЛЮЧ; УКАЗ ОБНУЛИТЬ(выход); n := 80H; i := 0; b := 72; длинаВхода := ДЛИНА(вход); ЕСЛИ учРег ТО СОЗДАТЬ(регБукв, длинаВхода) КОН; дл := 0; сч := длинаВхода; ПОВТОРЯТЬ УМЕНЬШИТЬ(сч); ЕСЛИ вход[сч] = 2DX ТО дл := сч; сч := 0 КОН ДО сч = 0; размерВыхода := РАЗМЕР(выход); ЕСЛИ размерВыхода < дл ТО Вывод.Цепь("Память для результата слишком мала."); ВОЗВРАТ КОН; ОТ сч := 0 ДО дл-1 ВЫП ЕСЛИ учРег ТО регБукв[сч] := ВЦЕЛ(вход[сч])-65 < 26 КОН; ЕСЛИ ВЦЕЛ(вход[сч]) >= 80H ТО Вывод.Цепь("Ошибочные входные данные."); ВОЗВРАТ КОН; выход[сч] := вход[сч] КОН; ЕСЛИ дл > 0 ТО сч := дл+1 ИНАЧЕ сч := 0 КОН; o := дл; ПОКА сч < длинаВхода ВЫП j := i; w := 1; k := 36; КОЛЬЦО ЕСЛИ сч >= длинаВхода ТО Вывод.Цепь("Ошибочные входные данные."); ВОЗВРАТ КОН; r := РаскодРазр(ВЦЕЛ(вход[сч])); УВЕЛИЧИТЬ(сч); ЕСЛИ r >= 36 ТО Вывод.Цепь("Ошибочные входные данные."); ВОЗВРАТ КОН; ЕСЛИ r > ЦЕЛЧАСТЬ((МАКС(ЦЕЛ) - i) / w) ТО Вывод.Цепь("Переполнение."); ВОЗВРАТ КОН; УВЕЛИЧИТЬ(i, r * w); ЕСЛИ k <= b ТО t := 1 ИНАЧЕ ЕСЛИ k >= b + 26 ТО t := 26 ИНАЧЕ t := k - b КОН КОН; ЕСЛИ r < t ТО ВЫХОД КОН; ЕСЛИ w > ЦЕЛЧАСТЬ(МАКС(ЦЕЛ) / (36 - t)) ТО Вывод.Цепь("Переполнение."); ВОЗВРАТ КОН; w := w * (36 - t); УВЕЛИЧИТЬ(k, 36) КОН; УВЕЛИЧИТЬ(o); b := Адапт(i - j, o, j = 0); ЕСЛИ ЦЕЛЧАСТЬ(i / o) > МАКС(ЦЕЛ) - n ТО Вывод.Цепь("Переполнение."); ВОЗВРАТ КОН; УВЕЛИЧИТЬ(n, УЗК(ВШИРЦЕЛ(ЦЕЛЧАСТЬ(i / o)))); i := i ОСТАТОК o; ЕСЛИ o >= размерВыхода ТО Вывод.Цепь("Память для результата слишком мала."); ВОЗВРАТ КОН; ЕСЛИ учРег ТО ОТ j := ДЛИНА(выход)-1 ДО i ПО -1 ВЫП регБукв[j+1] := регБукв[j] КОН; регБукв[i] := ВЦЕЛ(вход[сч-1])-65 < 26 КОН; Цепь.ВставитьЗнак(ВЗНАК(n), выход, i); УВЕЛИЧИТЬ(i); ЕСЛИ учРег ТО ОТ j := 0 ДО ДЛИНА(выход)-1 ВЫП ЕСЛИ регБукв[j] ТО выход[j] := Буква.ВЗаглавную(выход[j]) КОН КОН КОН КОН КОН Раскодировать; КОН Punycode.
ОписаниеПравить
В отделе «Punycode» представлены две задачи, выполняющие преобразование доменного имени:
- «Закодировать» — преобразует цепь знаков в Уникоде в код, например, «Русский» в «h1acbXfam», при этом второй параметр указывает, учитывать ли регистр букв при преобразовании или нет;
- «Раскодировать» — выполняет обратное преобразование, т.е. кода в цепь знаков, например, «h1alFfa9f» в «Россия», второй параметр также влияет на учитывание регистра.