正規表現におけるトークン
はじめに
正規表現で使用される小かっこは、式の要素をグループ化するだけでなく、そのグループに対して見つかった一致を "トークン" として指定します。トークンを使用すると、同じテキストの他の部分を一致させることができます。トークンを使用する利点の 1 つは、一致したことをトークンが記憶しているので、検索や置換の過程で一致したテキストを呼び出し、再使用することができる点です。
式内のトークンはそれぞれ、左から右に 1 ~ 255 の番号が付けられます。式の後半でトークンを参照するには、バックスラッシュ記号の後にトークン番号を付けます。たとえば、式内で 3 番目の小かっこにより作成されたトークンを参照する場合は、\3
とします。
簡単な例として、文字配列内で連続する同じ文字を検索する場合は、最初の文字をトークンとしてキャプチャし、直後に一致する文字を検索します。次に示す式では、regexp
で文字配列内の空白以外の文字が見つかるたびに、(\S)
句によってトークンが作成されます。式の 2 番目の部分の '\1'
では、1 番目の直後に出現する 2 番目の同じ文字が検索されます。
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'}
cell 配列 tok
に含まれる cell 配列には、それぞれトークンが含まれます。
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'}
cell 配列 ext
に含まれる数値配列には、それぞれトークンの開始インデックスと終了インデックスが含まれます。
ext{:}
ans = 11 11 ans = 26 26 ans = 35 35 ans = 57 57
別の例で、一致する HTML タグのペア (たとえば、<a>
と </a>
) とその間のテキストをキャプチャします。この例で使用される式は、次のとおりです。
expr = '<(\w+).*?>.*?</\1>';
この式の最初の部分 '<(\w+)'
では、開始山かっこ (<
) と、それに続く 1 つ以上のアルファベット、数字またはアンダースコア文字を一致させます。小かっこにより、開始山かっこに続くトークン文字がキャプチャされます。
式の 2 番目の部分、'.*?>.*?'
では、この 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)
このパターンには、トークンを生成する小かっこ付きの式が 3 つあります。検索を行うと、一致するごとに次のトークンが生成されます。
一致 | トークン 1 | トークン 2 |
---|---|---|
|
| |
|
|
|
|
| |
|
| |
|
|
|
最高レベルの小かっこのみが使用されています。たとえば、検索パターン and(y|rew)
でテキスト andrew
が見つかった場合は、トークン 1 に値 rew
が代入されます。ただし、検索パターン (and(y|rew))
が使用された場合は、トークン 1 に値 andrew
が代入されます。
一致しないトークン
評価対象のテキストに一致が見つからない、正規表現で指定されたトークンに対しては、regexp
と regexpi
によって、トークン出力として空の文字ベクトル (''
) と、文字列内でトークンが予想される位置をマークする範囲が返されます。
ここに示す例では、MATLAB® 関数 tempdir
から返されたパスを指定する文字ベクトルに対して regexp
を実行します。正規表現 expr
は、6 つのトークン指定子をもち、それぞれがパスの部分になっています。3 番目の指定子 [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
はトークンとして空の文字ベクトル (''
) と、トークン範囲を示す数値配列を返します。範囲の最初の数は、トークンが予想される位置をマークする文字列インデックスで、範囲の 2 番目の数は最初の数より 1 小さくなります。
この例の場合、空のトークンが式で 3 番目に指定されているため、3 番目に返されるトークンは空です。
tok{:}
ans = 1×6 cell array {'C:'} {'WINNT'} {0×0 char} {'bpascal'} {'LOCALS~1'} {'Temp'}
変数 ext
に返される 3 番目のトークンの範囲は、一致しない語句 Profiles
がパス内で始まる位置である 10 に設定された開始インデックスをもちます。範囲の終わりのインデックスは、開始インデックスより 1 小さく、9 に設定されます。
ext{:}
ans = 1 2 4 8 10 9 19 25 27 34 36 39
置換テキスト内のトークン
置換テキストでトークンを使用する場合は、\1
、\2
などの代わりに $1
、$2
などを使用してトークンを参照します。次の例では 2 つのトークンをキャプチャして、順序を逆にします。最初の $1
は 'Norma Jean'
であり、2 番目の $2
は 'Baker'
です。regexprep
では既定で、開始インデックスのベクトルではなく、変更された文字列が返されることに注意してください。
regexprep('Norma Jean Baker', '(\w+\s\w+)\s(\w+)', '$2, $1')
ans = 'Baker, Norma Jean'
名前付きキャプチャ
トークンに名前を代入すると、トークン番号の代入の追跡が不要になり、式内で多数のトークンを使用する場合に便利です。
式内の名前付きトークンを参照する場合は、数値による \1
、\2
などではなく、\k<name>
という構文を使用します。
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'