Main Content

正規表現におけるトークン

はじめに

正規表現で使用される小かっこは、式の要素をグループ化するだけでなく、そのグループに対して見つかった一致を "トークン" として指定します。トークンを使用すると、同じテキストの他の部分を一致させることができます。トークンを使用する利点の 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

andy

y

 

ted

t

d

andrew

rew

 

andy

y

 

ted

t

d

最高レベルの小かっこのみが使用されています。たとえば、検索パターン and(y|rew) でテキスト andrew が見つかった場合は、トークン 1 に値 rew が代入されます。ただし、検索パターン (and(y|rew)) が使用された場合は、トークン 1 に値 andrew が代入されます。

一致しないトークン

評価対象のテキストに一致が見つからない、正規表現で指定されたトークンに対しては、regexpregexpi によって、トークン出力として空の文字ベクトル ('') と、文字列内でトークンが予想される位置をマークする範囲が返されます。

ここに示す例では、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'

参考

| |

関連するトピック