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

Введение

В динамическом выражении можно сделать шаблон, который вы хотите 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 символы в каждом из векторов символов сохранены во входном массиве ячеек. Обратите внимание однако что количество Xs варьируется по каждому вектору символов. Если бы количество не варьировалось, вы могли бы использовать выражение X{n} указать, что вы хотите совпадать с n из этих символов. Но, постоянное значение n не работает в этом случае.

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

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 cellArray:

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'

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

| |

Похожие темы