パターン定義とキャプチャグループの使用
SenseTalkのパターン言語でパターンを定義するとき、パターン定義はElements of the SenseTalk Pattern Languageで述べられているように、複数の要素、またはサブパターンから作成できます。サブパターンをマークするために、その周りに中括弧を使用します。
キャプチャグループは次の3つの有用な目的に使用できます:
以下の構文を使用して、パターン内の各キャプチャグループに名前を付けることができます:
{ name : subPattern }
キャプチャグループの名前は省略することもでき、その場合、デフォルトの名前(Group_1、Group_2など)が割り当てられます。
重要: パターン全体が常にプロパティ名text
を持つマッチプロパティリストで報告されるため、text
をキャプチャグループ名として使用しないでください。
情報のキャプチャ
キャプチャグループの使用は、パターンマッチに関する追加情報をキャプチャすることを可能にします。キャプチャグループは、全体的なパターンマッチが行われたときに、マッチプロパティリストの一部としてキャプチャグループの具体的なマッチテキストとマッチの範囲を返します。
match()
やeveryMatch()
関数、およびmatch
チャンク表現を使用するとき、SenseTalkはマッチした完全なテキストとそのテキストがマッチしたソース内の範囲を含むプロパティリストを返します。キャプチャグループを使用すると、マッチプロパティリストにはマッチした各キャプチャグループに対して2つの追加プロパティが含まれます:
- name: This property has the actual name of the capture group, and the value is the text that was matched.
- name_range: A property with
_range
appended to the group name, and a value that is the range of characters where the group was matched.
これらの関数についての詳細情報は、Match()
, EveryMatch()
Functionsをご覧ください。
次の例は、キャプチャグループがないパターン定義を示しています:
set parenPattern to <"(" then some characters then ")">
put the match of parenPattern in "John Jacob (Jingleheimer) Smith"
この場合、parenPattern
は括弧で囲まれたテキストにマッチするシンプルなパターンです。その結果のマッチは次のとおりです:
(text:"(Jingleheimer)", text_range:"12" to "25")
同じパターンは、キャプチャグループを使用して定義することも可能です:
set parenPattern to <"(" then {content: some characters} then ")">
put the match of parenPattern in "John Jacob (Jingleheimer) Smith"
ここでは、パターンのsome characters
部分が中括弧で囲まれ、グループ名content
でラベル付けされています。その結果のマッチは次のとおりです:
(content:"Jingleheimer", content_range:"13" to "24", text:"(Jingleheimer)", text_range:"12" to "25")
text
とtext_range
プロパティは全体的なマッチに関する情報とともに引き続き存在しますが、content
とcontent_range
プロパティが括弧の間でマッチしたテキスト、つまりキャプチャグループに関する情報とともに追加されています。
パターンには、マッチしたパターンの異なる部分をキャプチャするための複数のキャプチャグループを含めることができます。通常、各キャプチャグループには異なる名前を付けるべきです。しかし、あなたのパターン定義がor
条件に基づく代替選択を使用する場合、その条件の両側でキャプチャグループに同じ名前を使用したい場合があります。そこでは、一方または他方だけが返されます。
例として、以下のコードは、括弧で囲まれているかどうかに関わらず、電話のエリアコードを表すパターンを定義します。
set areaCode to <({ac:3 digits} followed by non-digit) or ("(" then {ac:3 digits} then ")" then maybe space)>
この例では、キャプチャグループac
が二回登場します。それぞれor
演算子の両側に一回ずつです。
一部のキャプチャグループは、使用されなかったor
の代替部分に属している場合、全体のマッチの一部として参加しない場合があります。全体のマッチの一部として使用されないキャプチャグループは、マッチプロパティリストには報告されません。
過去のサブパターンマッチを参照する
キャプチャグループ内のサブパターンによってマッチしたテキストは、全体のパターン内で後でバックリファレンスとして使用することができます。これにより、同じテキストを再度マッチさせることができます。バックリファレンスは以下の形式を取ります。
{: name }
ここで、name
は過去のキャプチャグループの名前です。
例えば、以下のパターンは、テキストの中で二回連続して出現する単語を見つけるために使用できます。
set doubleWord to <word break, {word: word chars}, nonword chars, {:word}, word break>
put every instance of doubleWord in "Come to to Paris in the the spring"
この例では、ソース文字列から二つのマッチを表示します。
["to to","the the"]
パターンの最初の部分は、単語(単語区切り後の単語文字から非単語文字まで)をキャプチャし、それにグループ名word
を割り当てます。その後、パターンはバックリファレンス{:word}
を使用してキャプチャした値を参照します。
バックリファレンスが特に便利なもう一つの状況は、HTMLやXMLの中で一致するタグのペアを見つけることです。例えば、<body>
と</body>
のようなもので、その間に他の多数の<tag>
エントリーがあるかもしれません。キャプチャグループとバックリファレンスを使用してそのようなパターンを書く一つの方法はこちらです:
set tagPattern to < "<", {tag: chars}, ">", chars, "</", {:tag}, ">" >
名前のないバックリファレンス
各キャプチャグループに名前を割り当てずにバックリファレンスを使用することができます。これを行うには、{groupNum}
をバックリファレンスとして使用します。ここで、groupNum
はキャプチャグループの連続した番号です。したがって、{1}
はパターン内の最初のキャプチャグループの値を、{2}
は二つ目のグループを参照します。
例えば、上記の二重単語の例は、キャプチャグループに名前を付けずにこのように定義することができます:
set doubleWord to <word break, {word chars}, nonword chars, {1}, word break>
パターンマッチに基づくテキスト操作
キャプチャグループによってマッチした値は、Replace
コマンドとともに置換文字列で使用することができます。このアプローチはパターン内のバックリファレンスと似ています。つまり、置換文字列内で前のキャプチャグループへの参照、{:name}
を使用します。このテクニックを使用して、パターンマッチを様々な方法で変換することができます。ソースからのテキストを置換するか、または並べ替えることが可能です。
たとえば、次のような形式でLastName
、FirstName
の名前リストを考えてみてください:
set nameList to {{
Disney, Walter Elias
Earhart, Amelia
Einstein, Albert
Tolkien, J.R.R.
}}
課題は、各行の姓と名前の順序を逆にし、それらを区切るカンマを削除することです。まず、各名前にマッチし、関連する部分をキャプチャするパターンが必要です:
set namePattern to < line start, {lastname: chars}, ", ", {firstname: chars}, line end >
その後、Replace
コマンドの置換文字列内の名前付きキャプチャグループへの参照を使用して変換を実行できます:
replace namePattern in nameList with "{:firstname} {:lastname}"
put nameList
結果は変換されたリストとなります:
Walter Elias Disney
Amelia Earhart
Albert Einstein
J.R.R. Tolkien