понедельник, 14 января 2013 г.

Преобразование схожих русских и английских букв

Сходство некоторых русских и английских букв достаточно часто используется как средство защиты. Типичный пример, сайты тестирования. Отвечая на вопрос, а что выдаст программа:
#include <stdio.h>
int main()
{
 unsignеd int а, b, с;
 а = 1; b = 2; с = 3;
 рrintf("%d %d", а < b + с, а - b < с);
}
так и хочется открыть online-компилятор и проверить. Но открыв, например, liveworkspace.org, запустив данную программу мы получим кучу ошибок:
Compilation finished with errors:
source.cpp:4:4: error: stray '\320' in program
source.cpp:4:4: error: stray '\265' in program
...
source.cpp:6:2: error: stray '\201' in program
source.cpp: In function 'int main()':
source.cpp:4:4: error: 'unsign' was not declared in this scope
source.cpp:4:12: error: expected ';' before 'd'
source.cpp:5:5: error: expected primary-expression before '=' token
source.cpp:5:10: error: 'b' was not declared in this scope
source.cpp:5:20: error: expected primary-expression before '=' token
source.cpp:6:22: error: expected primary-expression before '<' token
source.cpp:6:30: error: expected primary-expression before ',' token
source.cpp:6:44: error: expected primary-expression before ')' token
source.cpp:6:44: error: 'rintf' was not declared in this scope
Или найдите слово "Маша" на данной странице в следующем фрагменте (через поиск):
Maшa eлa кaшy.

Встаёт вопрос: а как закодировать и декодировать подобное содержимое.

Основной приём в программах производящих (де-) кодирование - это замена одних букв на другие. Ниже я привожу какие буквы выглядят схоже (набор может быть расширен):
Русские буквы аАВсСеЕНкКМоОрРТхХу
Английские буквы aABcCeEHkKMoOpPTxXy

Используя эту простую идею, можно написать программу-фильтр, которая производит замену. Поскольку я часто использую perl для подобных целей, то привожу код соответствующего скрипта:
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
use Getopt::Long;

=comment
Программа позволяет преобразовать схожие английские буквы в русские и наоборот.

Параметр "--how" позволяет указать направление перевода:
 rus2eng - заменить русские буквы английскими
 eng2rus - заменить английские буквы русскими

Пример вызова:
perl -- d:\Проекты\Perl\similiar_letters.pl --how=rus2eng < e:\in.txt > e:\out.txt
perl -- d:\Проекты\Perl\similiar_letters.pl --how=eng2rus < e:\in.txt > e:\out.txt

Скрипт может вызываться из других программ. При вызове из Windows программ текст
в некоторых случаях передаётся в кодировке DOS (cp866) и читается в такой же.
Поэтому добавлен параметр "--dos" для предварительного преобразования.

Пример вызова:
perl -- d:\Проекты\Perl\similiar_letters.pl --dos --how=rus2eng < e:\in.txt > e:\out.txt
perl -- d:\Проекты\Perl\similiar_letters.pl --dos --how=eng2rus < e:\in.txt > e:\out.txt
=cut

my ($how, $dos) = ("", 0);
GetOptions(
 "how=s" => \$how,
 "dos"   => \$dos,
);

my $rus = "аАВсСеЕНкКМоОрРТхХу";
my $eng = "aABcCeEHkKMoOpPTxXy";

my ($from, $to) = ("", "");
if ($how eq "rus2eng") {
 $from = $rus;
 $to = $eng;
} elsif ($how eq "eng2rus") {
 $from = $eng;
 $to = $rus;
} else {
 print STDERR "unknown value of parameter 'how'\n";
}

undef $/;
$_ = <STDIN>; # не тоже самое, что <> поскольку во втором случае параметры скрипта влияют
$_ = Encode::encode("cp1251", Encode::decode("cp866",$_)) if ($dos);
eval "y/$from/$to/";
$_ = Encode::encode("cp866",Encode::decode("cp1251",$_)) if ($dos);
print STDOUT $_;


Комментариев нет:

Отправить комментарий