Динамические регулярные выражения

Введение

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

Можно включать любое количество динамических выражений в аргументах match_expr или replace_expr этих команд:

regexp(text, match_expr)
regexpi(text, match_expr)
regexprep(text, match_expr, replace_expr)

Как пример динамического выражения, следующая команда regexprep правильно заменяет термин internationalization на его сокращенную форму, i18n. Однако, чтобы использовать его на различном термине, таком как globalization, необходимо использовать различное выражение замены:

match_expr = '(^\w)(\w*)(\w$)';

replace_expr1 = '$118$3';
regexprep('internationalization', match_expr, replace_expr1)
ans =

    'i18n'
replace_expr2 = '$111$3';
regexprep('globalization', match_expr, replace_expr2)
ans =

    'g11n'

Используя динамическое выражение ${num2str(length($2))} позволяет вам основывать выражение замены на входном тексте так, чтобы вы не изменяли выражение каждый раз. Этот пример использует динамический заменяющий синтаксис ${cmd}.

match_expr = '(^\w)(\w*)(\w$)';
replace_expr = '$1${num2str(length($2))}$3';

regexprep('internationalization', match_expr, replace_expr)
ans =

    'i18n'
regexprep('globalization', match_expr, replace_expr)
ans =

    'g11n'

Когда проанализировано, динамическое выражение должно соответствовать полному, действительному регулярному выражению. Кроме того, динамические выражения соответствия, которые используют символ ESC наклонной черты влево (\), требуют двух наклонных черт влево: один для начального парсинга выражения, и один для полного соответствия. Круглые скобки, которые заключают динамические выражения, не создают группу фиксации.

Существует три формы динамических выражений, которые можно использовать в выражениях соответствия и одной форме для выражений замены, как описано в следующих разделах

Динамические выражения соответствия - (?? expr)

Оператор (??expr) анализирует выражение expr и вставляет результаты назад в выражение соответствия. MATLAB® затем выполняет измененное выражение соответствия.

Вот пример типа выражения, которое можно использовать с этим оператором:

chr = {'5XXXXX', '8XXXXXXXX', '1X'};
regexp(chr, '^(\d+)(??X{$1})$', 'match', 'once');

Цель этой конкретной команды состоит в том, чтобы определить местоположение серии символов X в каждом из векторов символов, сохраненных во входном массиве ячеек. Обратите внимание однако, что количество X s отличается по каждому вектору символов. Если бы количество не отличалось, вы могли бы использовать выражение X{n}, чтобы указать, что вы хотите совпадать с n этих символов. Но, постоянное значение n не работает в этом случае.

Решение, используемое здесь, состоит в том, чтобы получить ведущий номер количества (например, 5 в первом векторе символов массива ячеек) в лексеме, и затем использовать то количество в динамическом выражении. Динамическим выражением в этом примере является (??X{$1}), где $1 является значением, полученным маркерным \d+. Оператор {$1} делает квантор той символической стоимости. Поскольку выражение является динамическим, тот же шаблон работает над всеми тремя из входных векторов в массиве ячеек. С первым вектором вводимого символа regexp ищет пять символов X; со вторым это ищет восемь, и с третьим, это ищет всего один:

regexp(chr, '^(\d+)(??X{$1})$', 'match', 'once')
ans =

  1×3 cell array

    {'5XXXXX'}    {'8XXXXXXXX'}    {'1X'}

Команды, которые изменяют выражение соответствия - (??@cmd)

MATLAB использует оператор (??@cmd), чтобы включать результаты команды MATLAB в выражении соответствия. Эта команда должна возвратить термин, который может быть использован в рамках выражения соответствия.

Например, используйте динамическое выражение (??@flilplr($1)), чтобы определить местоположение палиндрома, “Никогда Нечетный или Даже”, который был встроен в больший вектор символов.

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

chr = lower(...
  'Find the palindrome Never Odd or Even in this string');

chr = regexprep(chr, '\W*', '')
chr =

    'findthepalindromeneveroddoreveninthisstring'

Найдите палиндром в векторе символов с помощью динамического выражения:

palindrome = regexp(chr, '(.{3,}).?(??@fliplr($1))', 'match')
palindrome =

  1×1 cell array

    {'neveroddoreven'}

Динамическое выражение инвертирует порядок букв, которые составляют вектор символов, и затем пытается совпадать с как можно большим количеством вектора обратного порядка. Это требует динамического выражения, потому что значение для $1 полагается на значение маркерного (.{3,}).

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

fun = @fliplr;

palindrome = regexp(chr, '(.{3,}).?(??@fun($1))', 'match')
palindrome =

  1×1 cell array

    {'neveroddoreven'}

Команды, которые служат функциональной цели - (?@cmd)

Оператор (?@cmd) задает команду MATLAB, которую regexp или regexprep должны запустить при парсинге полного выражения соответствия. В отличие от других динамических выражений в MATLAB, этот оператор не изменяет содержимое выражения, в котором это используется. Вместо этого можно использовать эту функциональность, чтобы заставить MATLAB сообщать, что продвигается, это берет, когда это анализирует содержимое одного из регулярных выражений. Эта функциональность может быть полезной в диагностировании ваших регулярных выражений.

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

regexp('mississippi', '\w*(\w)\1\w*', 'match')
ans =

  1×1 cell array

    {'mississippi'}

Чтобы отследить точные шаги, которые MATLAB делает в определении соответствия, пример вставляет короткий скрипт (?@disp($1)) в выражение, чтобы отобразить символы, которые наконец составляют соответствие. Поскольку пример использует жадные кванторы, MATLAB пытается совпадать с как можно большим количеством вектора символов. Так, даже при том, что MATLAB находит соответствие к началу строки, это продолжает искать больше соответствий, пока это не прибывает в самый конец строки. Оттуда, это поддерживает через буквы i затем p и следующий p, останавливающийся в той точке, потому что соответствие наконец удовлетворено:

regexp('mississippi', '\w*(\w)(?@disp($1))\1\w*', 'match')
i
p
p

ans =

  1×1 cell array

    {'mississippi'}

Теперь попробуйте тот же пример снова, на этот раз делая первый квантор ленивым (*?). Снова, MATLAB делает то же соответствие:

regexp('mississippi', '\w*?(\w)\1\w*', 'match')
ans =

  1×1 cell array

    {'mississippi'}

Но путем вставки динамического скрипта, вы видите, что на этот раз, MATLAB совпадал с текстом вполне по-другому. В этом случае MATLAB использует самое первое соответствие, которое он может найти и даже не рассматривает остальную часть текста:

regexp('mississippi', '\w*?(\w)(?@disp($1))\1\w*', 'match')
m
i
s

ans =

  1×1 cell array

    {'mississippi'}

Чтобы продемонстрировать, насколько универсальный этот тип динамического выражения может быть, рассмотрите следующий пример, который прогрессивно собирает массив ячеек, когда MATLAB итеративно анализирует входной текст. Оператор (?!), найденный в конце выражения, является на самом деле пустым предварительным оператором и обеспечивает отказ в каждой итерации. Этот принудительный отказ необходим, если вы хотите проследить шаги, которые MATLAB делает, чтобы разрешить выражение.

MATLAB делает, много проходят через входной текст, каждый раз пробуя другую комбинацию букв, чтобы видеть, может ли подгонка лучше, чем последнее соответствие быть найдена. На любых передачах, в которых никакие соответствия не найдены, результаты испытаний в пустом символьном векторе. Динамический скрипт (?@if(~isempty($&))) служит, чтобы не использовать пустые символьные вектора от массива ячеек matches:

matches = {};
expr = ['(Euler\s)?(Cauchy\s)?(Boole)?(?@if(~isempty($&)),' ...
   'matches{end+1}=$&;end)(?!)'];

regexp('Euler Cauchy Boole', expr);

matches
matches =

  1×6 cell array

    {'Euler Cauchy Bo…'}    {'Euler Cauchy '}    {'Euler '}    {'Cauchy Boole'}    {'Cauchy '}    {'Boole'}

$& операторов (или эквивалентный $0), $` и $' относится к той части входного текста, который является в настоящее время соответствием, все символы, которые предшествуют текущему соответствию и всем символам, чтобы следовать за текущим соответствием, соответственно. Эти операторы иногда полезны при работе с динамическими выражениями, особенно те, которые используют оператор (?@cmd).

Этот пример анализирует входной текст, ища букву g. В каждой итерации через текст regexp сравнивает текущий символ с g, и не нахождение его, усовершенствования к следующему символу. Пример отслеживает прогресс сканирования через текст путем маркировки текущего местоположения, проанализированного с символом ^.

($` и операторы получают ту часть текста, который предшествует и следует за текущим местоположением парсинга. Вам нужны два одинарных кавычек ($''), чтобы выразить последовательность , когда это появляется в рамках текста.)

chr = 'abcdefghij';
expr = '(?@disp(sprintf(''starting match: [%s^%s]'',$`,$'')))g';

regexp(chr, expr, 'once');
starting match: [^abcdefghij]
starting match: [a^bcdefghij]
starting match: [ab^cdefghij]
starting match: [abc^defghij]
starting match: [abcd^efghij]
starting match: [abcde^fghij]
starting match: [abcdef^ghij]

Команды в выражениях замены — $ {cmd}

Оператор ${cmd} изменяет содержимое заменяющего шаблона регулярного выражения, делая этот шаблон адаптируемым к параметрам во входном тексте, который может отличаться от одного использования до следующего. Как с другими динамическими выражениями, используемыми в MATLAB, можно включать любое количество этих выражений в полном выражении замены.

В вызове regexprep, показанном здесь, заменяющим шаблоном является '${convertMe($1,$2)}'. В этом случае целый заменяющий шаблон является динамическим выражением:

regexprep('This highway is 125 miles long', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}');

Динамическое выражение говорит MATLAB выполнять функцию с именем convertMe с помощью этих двух лексем (\d+\.?\d*) и (\w+), выведенный из соответствующего текста, как входные параметры в вызове convertMe. Заменяющий шаблон требует динамического выражения, потому что значения $1 и $2 сгенерированы во времени выполнения.

Следующий пример задает файл с именем convertMe, который преобразовывает измерения от имперских модулей до метрики.

function valout  = convertMe(valin, units)
switch(units)
    case 'inches'
        fun = @(in)in .* 2.54;
        uout = 'centimeters';
    case 'miles'
        fun = @(mi)mi .* 1.6093;
        uout = 'kilometers';
    case 'pounds'
        fun = @(lb)lb .* 0.4536;
        uout = 'kilograms';
    case 'pints'
        fun = @(pt)pt .* 0.4731;
        uout = 'litres';
    case 'ounces'
        fun = @(oz)oz .* 28.35;
        uout = 'grams';
end
val = fun(str2num(valin));
valout = [num2str(val) ' ' uout];
end

В командной строке вызовите функцию convertMe от regexprep, передающего в значениях для количества, которое будет преобразовано и имя имперского модуля:

regexprep('This highway is 125 miles long', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}')
ans =

    'This highway is 201.1625 kilometers long'
regexprep('This pitcher holds 2.5 pints of water', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}')
ans =

    'This pitcher holds 1.1828 litres of water'
regexprep('This stone weighs about 10 pounds', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}')
ans =

    'This stone weighs about 4.536 kilograms'

Как с оператором (??@ ), обсужденным в более раннем разделе, оператор ${ } имеет доступ к переменным в в настоящее время активной рабочей области. Следующая команда regexprep использует массив A, заданный в базовом рабочем пространстве:

A = magic(3)
A =

     8     1     6
     3     5     7
     4     9     2
regexprep('The columns of matrix _nam are _val', ...
          {'_nam', '_val'}, ...
          {'A', '${sprintf(''%d%d%d '', A)}'})
ans =

    'The columns of matrix A are 834 159 672'

Смотрите также

| |

Похожие темы