Как создать регулярные выражения в Perl, нечувствительные к полуширокой/полноширокой форме?

Вопрос или проблема

В Perl, /a/i соответствует как A, так и a, так что мне не нужно писать /A|a/.

Как легко написать /4|4/ ?

Да, я говорю о

$ unicode 4 4|grep U+
U+FF14 FULLWIDTH DIGIT FOUR
U+0034 DIGIT FOUR

Должен ли я повторять каждую строку,

    if (/大茅埔段32(7|8|9).地/ ||
        /大茅埔段32(7|8|9).地/)     {...}

или есть ли более лучший способ?
Это не так много символов, https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block)

Кстати, как сделать так, чтобы

$ echo A|perl -pwle 's/a/x/i'

соответствовало? (Обе A широкие.)

Я не думаю, что в perl есть встроенная поддержка для сопоставления, независимого от ширины, вам нужно заменить a на [aa] для всех символов, у которых есть двойная ширина.

Для вашего случая использования if (/大茅埔段32[789].地/), вы можете использовать формы нормализации NFKC или NFKD, которые изменят эти полные или половинные символы на их нормальное представление (будь то одинарная ширина, как для цифр, или двойная, как для китайских иероглифов), и также скомпозируют или декомпозируют символ соответственно, позволяя вам, например, сопоставить либо предкомпозированные, либо декомпозированные варианты символа é.

$ printf '大茅埔段327-地Ste\u301phane' |
  perl -MUnicode::Normalize=NFKC -C -Mutf8 -lwne '
    print "yes" if NFKC($_) =~ /大茅埔段32[789].地STÉPHANE/i'
yes

Что касается вашего другого вопроса (и это также касается и вышеупомянутого), обратите внимание, что perl по умолчанию предполагает iso8859-1, также известную как latin1, кодировку для ввода/вывода и кода. В iso8859-1 нет символов с двойной шириной. Предположительно, вы используете эти символы в кодировке UTF-8 и находитесь в локали, использующей UTF-8 в качестве чармепы, поэтому вам нужно:

$ echo 'A'|perl -Mutf8 -C -pwle 's/a/x/i'
x

С -C чтобы указать perl предполагать UTF-8 ввод/вывод, пока это то, что используется в локали, и -Mutf8 чтобы указать, что код (здесь переданный для -e) закодирован в UTF-8.

Или напишите это так:

$ echo 'A'|perl -C -pwle 's/\x{FF41}/x/i'
x

Где код остается в ASCII, так что вам не нужно -Mutf8, и символ с двойной шириной указан его значением широкого символа.

Ответ или решение

Вопрос о том, как сделать регулярные выражения на Perl нечувствительными к полуширинным и полнымширинным формам, является актуальной задачей, особенно в контексте работы с многобайтовыми наборами символов, такими как Unicode. В Perl, мы легко можем обрабатывать регистрозависимость с использованием модификатора /i, но что делать, когда речь идет о ширине символов? Рассмотрим это подробно, используя подход TEA (теория, пример, применение).

Теория

Unicode предоставляет различные формы представления символов, включая полную и полуширинную формы. Символы с кодами U+FF00 и выше, такие как FULLWIDTH DIGIT FOUR (U+FF14), визуально выглядят шире, чем их полуширинные аналоги — например, DIGIT FOUR (U+0034).

В Perl отсутствует встроенная функциональность, которая позволила бы автоматически сделать регулярные выражения независимыми от ширины символов без явного указания всех возможных вариантов каждого символа. Однако, мы можем использовать нормализацию Unicode для перевода текстов в форму, где все допустимые варианты будут представлены в одном виде. Для этого могут использоваться формы нормализации NFKC или NFKD (совместимая нормализация с декомпозицией).

Пример

Чтобы привести текст в принятую форму, вы можете воспользоваться модулем Unicode::Normalize в Perl. Он позволяет преобразовать текст к нормализованной форме, что упрощает задачу сопоставления строк:

use Unicode::Normalize 'NFKC';

my $text = '大茅埔段327-地Ste\u301phane';
if (NFKC($text) =~ /大茅埔段32[789]-地STÉPHANE/i) {
    print "Match found!\n";
}

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

Применение

  1. Настройка среды: Убедитесь, что Perl ожидает ввод/вывод в UTF-8. Это можно сделать с помощью флага -C, инициализируя скрипт с этого флага, чтобы он понимал, что текст идет в UTF-8.

    perl -CIO -Mutf8 script.pl
  2. Нормализация: Применяйте нормализацию Unicode ко всем строкам, с которыми планируете работать. Это сделает вашу программу менее зависимой от формы ввода текста.

    use Unicode::Normalize 'NFKC';
    
    while (<>) {
        my $norm_text = NFKC($_);
        if ($norm_text =~ /заданное_регулярное_выражение/) {
            print "Совпадение найдено\n";
        }
    }
  3. Специальные случаи: Для букв и чисел можно явно указать не только их ASCII и полные формы, но и возможные коды, используя их числа в Unicode.

    if ($text =~ /\x{FF14}|\x{0034}/) {
       print "Совпадение цифры 4 найдено\n";
    }

Значительным аспектом является также учёт кодировок и локалей. Убедитесь, что весь ваш стек программ поддерживает и работает с UTF-8, и конфигурация локалей указывает на правильную кодировку, чтобы избежать проблем с искажением символов.

Заключение

Работа с полными и полуширинными формами символов в Perl требует тщательного подхода к нормализации и использовании специальных модулей для упрощения задач по сопоставлению строк. Внимание к деталям в вопросах кодировок и обработке Unicode — ключ к созданию надёжных и эффективных скриптов, которые будут корректно обрабатывать текст в различных формах. Следуя представленным рекомендациям, вы сможете более гибко и эффективно работать с текстовыми данными в Perl.

Оцените материал
Добавить комментарий

Капча загружается...