Круглые скобки, используемые в регулярном выражении, не только группируют элементы этого выражения вместе, но также обозначают любые совпадения, найденные для этой группы, как маркеры. Маркеры можно использовать для сопоставления с другими частями того же текста. Одно из преимуществ использования токенов заключается в том, что они запоминают то, что им соответствует, так что вы можете вспомнить и повторно использовать согласованный текст в процессе поиска или замены.
Каждому маркеру в выражении присваивается номер, начинающийся с 1 и идущий слева направо. Чтобы сделать ссылку на маркер позже в выражении, обратитесь к нему с помощью обратной косой черты, за которой следует номер маркера. Например, при ссылке на маркер, сгенерированный третьим набором скобок в выражении, используйте \3.
В качестве простого примера, если вы хотите найти идентичные последовательные буквы в массиве символов, вы можете захватить первую букву в качестве маркера, а затем найти соответствующий символ сразу после этого. В приведенном ниже выражении (\S) фраза создает маркер всякий раз, когда regexp соответствует любому символу, не находящемуся в пространстве символов в массиве символов. Вторая часть выражения, '\1', ищет второй экземпляр того же символа сразу после первого.
poe = ['While I nodded, nearly napping, ' ... 'suddenly there came a tapping,']; [mat,tok,ext] = regexp(poe, '(\S)\1', 'match', ... 'tokens', 'tokenExtents'); mat
mat =
1×4 cell array
{'dd'} {'pp'} {'dd'} {'pp'}
Массив ячеек tok содержит массивы ячеек, каждый из которых содержит маркер.
tok{:}
ans =
1×1 cell array
{'d'}
ans =
1×1 cell array
{'p'}
ans =
1×1 cell array
{'d'}
ans =
1×1 cell array
{'p'}
Массив ячеек ext содержит числовые массивы, каждый из которых содержит начальный и конечный индексы маркера.
ext{:}
ans =
11 11
ans =
26 26
ans =
35 35
ans =
57 57
В другом примере захватывают пары соответствующих HTML-тегов (например, <a> и </a>) и текст между ними. Выражение, используемое в этом примере:
expr = '<(\w+).*?>.*?</\1>';
Первая часть выражения, '<(\w+)', соответствует угловой скобке открытия (<), а затем один или несколько буквенных, цифровых символов или символов подчеркивания. В круглых скобках содержатся символы маркеров, следующие за угловой скобкой открытия.
Вторая часть выражения, '.*?>.*?', соответствует остальной части этого HTML-тега (символы до >) и любые символы, которые могут предшествовать следующей угловой скобке открытия.
Последняя часть, '</\1>', соответствует всем символам в завершающем теге HTML. Этот тег состоит из последовательности </tag>, где tag - это все символы, которые были захвачены в качестве маркера.
hstr = '<!comment><a name="752507"></a><b>Default</b><br>'; expr = '<(\w+).*?>.*?</\1>'; [mat,tok] = regexp(hstr, expr, 'match', 'tokens'); mat{:}
ans =
'<a name="752507"></a>'
ans =
'<b>Default</b>'
tok{:}ans =
1×1 cell array
{'a'}
ans =
1×1 cell array
{'b'}
Ниже приведен пример назначения значений маркерам. Предположим, что вы собираетесь искать следующий текст:
andy ted bob jim andrew andy ted mark
Вы выбираете поиск по приведенному выше тексту со следующим шаблоном поиска:
and(y|rew)|(t)e(d)
Этот шаблон имеет три выражения в скобках, которые создают маркеры. При выполнении поиска для каждого совпадения создаются следующие маркеры.
Матч | Маркер 1 | Маркер 2 |
|---|---|---|
|
| |
|
|
|
|
| |
|
| |
|
|
|
Используются только скобки верхнего уровня. Например, если шаблон поиска and(y|rew) находит текст andrew, маркеру 1 присвоено значение rew. Однако, если шаблон поиска (and(y|rew)) используется, маркеру 1 присваивается значение andrew.
Для маркеров, указанных в регулярном выражении, которые не совпадают в вычисляемом тексте, regexp и regexpi возврат пустого символьного вектора ('') в качестве вывода маркера и экстента, который помечает позицию в строке, где ожидался маркер.
Приведенный здесь пример выполняется regexp для вектора символов, указывающего путь, возвращаемый из MATLAB
®tempdir функция. Регулярное выражение expr включает шесть спецификаторов маркеров, по одному для каждой части пути. Третий спецификатор [a-z]+ не соответствует вектору символов, поскольку эта часть пути, Profiles, начинается с прописной буквы:
chr = tempdir
chr =
'C:\WINNT\Profiles\bpascal\LOCALS~1\Temp\'
expr = ['([A-Z]:)\\(WINNT)\\([a-z]+)?.*\\' ... '([a-z]+)\\([A-Z]+~\d)\\(Temp)\\']; [tok, ext] = regexp(chr, expr, 'tokens', 'tokenExtents');
Если маркер не найден в тексте, regexp возвращает пустой символьный вектор ('') в качестве маркера и числового массива с расширением маркера. Первое число экстента - это строковый индекс, который отмечает, где ожидался маркер, а второе число экстента равно на единицу меньше первого.
В этом примере пустой токен является третьим, указанным в выражении, поэтому третий возвращенный токен является пустым:
tok{:}
ans =
1×6 cell array
{'C:'} {'WINNT'} {0×0 char} {'bpascal'} {'LOCALS~1'} {'Temp'}
Третий экстент маркера, возвращенный в переменной ext имеет начальный индекс, равный 10, где несопоставимый член, Profiles, начинается на пути. Конечный индекс экстента установлен на единицу меньше начального индекса, или на 9:
ext{:}
ans =
1 2
4 8
10 9
19 25
27 34
36 39
При использовании маркеров в тексте замены ссылайтесь на них с помощью $1, $2и т.д. вместо \1, \2и т.д. Этот пример захватывает два маркера и изменяет их порядок. Первый, $1является 'Norma Jean' и второй, $2является 'Baker'. Обратите внимание, что regexprep возвращает измененный текст, а не вектор начальных индексов.
regexprep('Norma Jean Baker', '(\w+\s\w+)\s(\w+)', '$2, $1')
ans =
'Baker, Norma Jean'
Если в выражениях используется много маркеров, может быть полезно назначить им имена, а не отслеживать, какой номер маркера назначен какому маркеру.
При ссылке на именованный маркер в выражении используйте синтаксис \k<name> вместо числового \1, \2и т.д.:
poe = ['While I nodded, nearly napping, ' ... 'suddenly there came a tapping,']; regexp(poe, '(?<anychar>.)\k<anychar>', 'match')
ans =
1×4 cell array
{'dd'} {'pp'} {'dd'} {'pp'}
Именованные маркеры также могут быть полезны при маркировке выходных данных функций регулярного выражения MATLAB. Это особенно верно при обработке многих фрагментов текста.
Например, разбор различных частей адресов улиц из нескольких векторов символов. Каждому маркеру в выражении присваивается короткое имя:
chr1 = '134 Main Street, Boulder, CO, 14923'; chr2 = '26 Walnut Road, Topeka, KA, 25384'; chr3 = '847 Industrial Drive, Elizabeth, NJ, 73548'; p1 = '(?<adrs>\d+\s\S+\s(Road|Street|Avenue|Drive))'; p2 = '(?<city>[A-Z][a-z]+)'; p3 = '(?<state>[A-Z]{2})'; p4 = '(?<zip>\d{5})'; expr = [p1 ', ' p2 ', ' p3 ', ' p4];
Как показывают следующие результаты, можно упростить работу с выводом с помощью именованных маркеров.
loc1 = regexp(chr1, expr, 'names')
loc1 =
struct with fields:
adrs: '134 Main Street'
city: 'Boulder'
state: 'CO'
zip: '14923'
loc2 = regexp(chr2, expr, 'names')
loc2 =
struct with fields:
adrs: '26 Walnut Road'
city: 'Topeka'
state: 'KA'
zip: '25384'
loc3 = regexp(chr3, expr, 'names')
loc3 =
struct with fields:
adrs: '847 Industrial Drive'
city: 'Elizabeth'
state: 'NJ'
zip: '73548'