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

Введение

В динамическом выражении можно создать шаблон, который вы хотите 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'

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

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

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

)

The (??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 персонажи; со вторым он ищет восемь, а с третьим - всего один:

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

  1×3 cell array

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

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

)

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

Для примера используйте динамическое выражение (??@flilplr($1)) чтобы найти палиндром, «Never Odd or Even», который был встроен в больший вектор символов.

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

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

)

The (?@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 итеративно анализирует входной текст. The (?!) оператор, найденный в конце выражения, на самом деле является пустым оператором lookahead и приводит к отказу при каждой итерации. Этот принудительный отказ необходим, если необходимо проследить шаги, которые 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, и не найдя его, продвигается к следующему символу. Пример отслеживает прогресс скана через текст, помечая текущее место, в котором выполняется синтаксический анализ ^ символ.

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

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

}

The ${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'

См. также

| |

Похожие темы