exponenta event banner

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

Введение

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

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

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

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

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

)

(?@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'

См. также

| |

Связанные темы