シェルスクリプトで役立つテキスト文字列のパターンマッチングの基礎Beginner's Guide(2/5 ページ)

» 2009年01月06日 14時46分 公開
[Peter Seebach,SourceForge.JP Magazine]
SourceForge.JP Magazine

パターンマッチングの基礎

 パターンに用いる通常キャラクタの大部分は、自分自身と同じ文字とのみ一致すると判定され、ほかの文字と一致すると見なされることはない。例えばhelloというパターンに対して一致する文字列はhelloだけである。また目的とする文字列の一部だけに一致するパターンがあっても、それは当該文字列に一致しているとは見なされず、先の例で言うと、「hello, world」というテキストに対しhelloは一致していないと判定される。つまりあるパターンが特定の文字列に一致するには、後記の2つの条件を満たしていなくてはならない。

  • パターンの構成キャラクタが、文字列側のものと一致している
  • 文字列の構成キャラクタが、パターン側のものと一致している

 ただしパターンの有す機能がこれだけであれば、それは単純な文字列比較を別の単語で言い換えただけに過ぎず、この章の残りの部分も「空白文字を挟んで連続した非空白文字のブロックは……と呼ばれ」といった埋め草的な解説でお茶を濁すか、あるいは美味しいクッキーの焼き方というクッキングレシピでも書き込んでおけばいいはずだ。残念ながら実際にはそうなってはおらず、パターン中では自分自身以外のキャラクタとも一致する特殊な記号が使えるのであり、こうしたパターン中で特殊な意味を有すキャラクタ群はワイルドカード(wildcard)あるいはメタキャラクタ(metacharacter)と呼ばれている。

 ワイルドカードという表現については、特殊記号の中でも任意のキャラクタと一致するものだけに限定すべきだという意見も一部から出されているが、シェル内にて特殊な機能を果たすキャラクタ群との混同を避けるため、ここで行うパターンについての解説ではそうした制限を設けることなく、この種の記号すべてをワイルドカードと呼称しておく。

 いずれにせよワイルドカードの存在は、先に提示した2つの基本ルールを複雑なものとしてしまう。なぜならパターン中の単一キャラクタが長大な文字列と一致することもあれば、逆にパターン中に配された一連のキャラクタ群がわずか1文字分のキャラクタだけに一致したり、まったく一致しなかったりする結果となるかもしれないからだ。重要なのは、対象となる文字列を取りこぼすようなミスマッチ部が存在しない対応関係となれるかという点である。

 ワイルドカードのうち最も多用される記号は、任意の1キャラクタに一致する疑問符(?)および、空白文字列も含めた任意長の文字列に一致するアスタリスク(*)である。

 実際のパターンにおける?の使用法は簡単で、その位置には1文字分のキャラクタが入ることは分かっているが具体的にどのキャラクタかは不明、という個所に用いればいい。例えば、ユーザーによってはあいさつの言葉にhalloやhulloといった単語を使う者もいるが、h?lloというパターンを使えばこうした表記にも対応できるはずである。ただしこうした指定法には2つの問題が潜んでいる。1つ目の問題として、例えば先のようなタイプのユーザーを扱う場合は、hello, thereやhello little computerないしhello how do i send emailといった冗長な表現が使われる傾向が見られるはずだ。つまりこれらの文字列があいさつ関連の文面であるかを判定するのであれば、文末が特定の単語ないしそうした単語プラスアルファで終わるか、という指定をする必要が生じてくる。

 そうした処理に利用できるのが*である。*は任意長の文字列と一致するので、hello*というパターンを用いれば、hello単体だけでなくhello以降に何らかの文字列が続くテキストとのマッチングが行える。ただしこのパターンもwell, helloという文字列には一致しない。それはhelloの前にキャラクタがあるテキストに対するマッチングの指定がないためである。そのため、どのような位置であれ特定の単語が出ているテキストを検出したい、という場合はアスタリスクを前後両方に配したパターンを使うのが定石であり、ここの例で言うと*hello*としておけば広範なあいさつ文にマッチングするはずだ。

 これら2つのワイルドカードを組み合わせると、文字列の長さそのほかの要件がより不確かなマッチングをさせることも可能である。またhello ?*というパターンはhello worldには一致するが単独のhelloだけには一致しない。ただしこのパターンについては、また別の問題が生じることになる。それは半角の空白文字を示すキャラクタは、パターンでは特殊な意味を有さないがシェルでは特殊な意味を有しているためだ。つまりこのパターンを引用符で囲んでおかなかった場合、シェルにより複数の単語に分割されることで意図したマッチングが行えなくなってしまうのだが、逆に引用符で囲んだ場合シェルはワイルドカードを無視してしまうというジレンマが生じるのである。この問題にかんしては、空白文字を引用符で囲んでおくか、ワイルドカードは引用符で囲まないようにするという2つの対策が存在し、この場合の指定についてはhello" "?*または"hello "?*と記述しておけばいい。

 シェルがパターンマッチングを実行するコンテクスト(caseステートメントなど)については変数置換の分割が行われないので、変数置換にまつわる空白文字を気にする必要はない(ただしzshの場合shエミュレーションモードを使用しない状況での結果は異なってくる)。

新しいことをはじめる前には「Beginner's Guide」で知識を得てみませんか?


Copyright © 2010 OSDN Corporation, All Rights Reserved.

注目のテーマ