文字列パターンの操作
Wolfram言語の一般的な記号文字列パターンを使って,強力な文字列操作を効率よく行うことができる.このドキュメントは,文字列パターンの詳細について,使用法と実装に関するノートを含めて説明するものであり,ヘルプシステム他の箇所では扱われていない点を特に詳述する.
Wolfram言語の文字列パターンは,同じコンストラクトを使ってテキスト文字列中のパターンを記述する.文字列を文字が連続するものと考えて,一般的なWolfram言語パターンの原則を適用することができる.さらに,文字列特有のパターンコンストラクトもいくつかある:
StringMatchQ["s",patt] | s が patt にマッチするかどうか判定する |
StringFreeQ["s",patt] | s が patt にマッチする文字列が含まれていないかどうか判定する |
StringCases["s",patt] | patt 中の s の部分文字列のリストを与える |
StringCases["s",lhs->rhs] | 各 lhs を rhs で置き換える |
StringPosition["s",patt] | patt にマッチする部分文字列の位置のリストを与える |
StringCount["s",patt] | いくつの部分文字列が patt にマッチするか数える |
StringReplace["s",lhs->rhs] | lhs にマッチするすべての部分文字列を置き換える |
StringReplaceList["s",lhs->rhs] | lhs を置換するすべての方法をリストする |
StringSplit["s",patt] | patt にマッチするすべての部分文字列のところで s を分割する |
StringSplit["s",lhs->rhs] | lhs で分割し rhs を挿入する |
一般的な文字列パターンは,Wolfram言語のパターンオブジェクトに類似のパターンオブジェクトによって形成される.複数のパターンオブジェクトの結合にはStringExpression演算子~~を用いる:
文字列で使うことができるオブジェクトのリストは,通常のWolfram言語パターンのリストとほぼ一致する.文字列パターンに関しては,文字列は一連の文字とみなされる.すなわち,"abc"は,通常のパターンコンストラクトが適用できるString[a,b,c]のようなものとみなされる.
"string" | 文字列 |
_ | 単一の文字 |
__ | 1つまたは複数の文字の入った部分文字列 |
___ | 文字が入ったまたは入らない部分文字列 |
x_
,
x__
,
x___ | x という名の部分文字列 |
x:pattern | x という名のパターン |
pattern.. | 1回あるいは複数回繰り返されたパターン |
pattern... | 繰り返されたあるいは繰り返されなかったパターン |
{patt1,patt2,…} または patt1patt2… | patti の少なくとも1つにマッチするパターン |
patt/;cond | cond を評価するとTrueになるパターン |
pattern?test | 各文字について test がTrueを返すパターン |
Whitespace | 空白類文字の文字列 |
NumberString | 数の文字 |
DatePattern[spec] | 日付の文字列 |
charobj | 文字のクラスを繰り返すオブジェクト(以下参照) |
RegularExpression["regexp"] | 正規表現にマッチする部分文字列 |
StringExpression[…] | 任意の文字列式 |
{c1,c2,…} | "ci"のいずれか |
Characters["c1c2…"] | "ci"のいずれか |
CharacterRange["c1","c2"] | "c1"から"c2" |
HexadecimalCharacter | 16進数字0–9,a–f,A–F |
DigitCharacter | 0から9までの数字 |
LetterCharacter | 文字 |
WhitespaceCharacter | スペース,改行,タブ,その他の空白類文字 |
WordCharacter | 文字または数字 |
Except[p] | p に一致するもの以外の任意の文字 |
StartOfString | 文字列全体の先頭 |
EndOfString | 文字列全体の末尾 |
StartOfLine | 行頭 |
EndOfLine | 行末 |
WordBoundary | 文字記号とその他の境界 |
Except[WordBoundary] | 文字の境界以外の任意の場所 |
_,__,___のワイルドカードは,改行を含むどの文字にもマッチする.改行以外のすべての文字にマッチするようにするのには(正規表現の"."のように),Except["\n"],Except["\n"]..,Except["\n"]...を使う:
{"a","b","c"}のようなパターンのリストは,"a" "b" "c"のような代替物のリストと等価である.CharactersやCharacterRangeのような関数を文字クラスの指定に使うことができるので,これは便利である:
Condition(/;)が使われると,Wolfram言語の他の部分に関する限り,これに含まれるパターンは文字列として扱われる.このため,場合によってはToExpressionを使わなければならないことがある:
通常の文字列パターンにRegularExpressionオブジェクトを挿入することができる:
StringExpressionオブジェクトはネストさせることができる:
文字列パターンのExceptコンストラクトは,単一の文字,あるいは単一の文字クラスを表す単一引数を取る.
異なる長さのパターン(__とpatt..等)をマッチさせようとするときは,デフォルトで,可能な最長マッチがまず試される.最初に最短マッチを試させるのには,パターンの関連箇所をShortest[ ]で包み込む:
何らかの理由で最短マッチ中の最長マッチが必要な場合には,Longestを使うことができる:
Longestを使う代りにパターンを書き換えてもよい:
正規表現のシンタックスは,その元になっているPCRE(Perl準拠正規表現)ライブラリに従っている.このライブラリはPerlのシンタックスにきわめて近い(詳細は[1]を参照のこと). Wolfram言語の正規表現は RegularExpressionという頭部で示される.
c | 文字通りの文字 c |
. | 新規行以外の任意の文字 |
[c1c2…] | ci 中の任意の文字 |
[c1-c2] | c1から c2の範囲の任意の文字 |
[^c1c2…] | ci 以外の任意の文字 |
p* | 繰り返されたあるいは繰り返されなかった p |
p+ | 繰り返された p |
p? | 現れたあるいは現れなかった p |
p{m,n} | m 回から n 回繰り返された p |
p*?
,
p+?
,
p?? | マッチする最短の文字列 |
p*+
,
p++
,
p?+ | プログレッシブマッチ |
(p1p2…) | p1, p2, …にマッチする文字列 |
p1p2 | p1 あるいは p2にマッチする文字列 |
\\d | 0から9までの数字 |
\\D | 数字ではないもの |
\\s | スペース,改行,タブ,その他の空白類 |
\\S | 空白類文字ではないもの |
\\w | 文字記号(文字,数字,あるいは _) |
\\W | 非文字記号 |
[[:class:]] | 名前の付いたクラス中の記号 |
[^[:class:]] | 名前の付いたクラスには含まれない記号 |
^ | 文字列(あるいは行)の先頭 |
$ | 文字列(あるいは行)の末尾 |
\\A | 文字列の先頭 |
\\z | 文字列の末尾 |
\\Z | 文字列の末尾(はじめに改行文字を1字許す) |
\\b | 語の区切り |
\\B | 語の区切り以外の任意の場所 |
(?i) | 大文字小文字を等しいものとして扱う(大文字小文字の区別をしない) |
(?m) | ^と$が行の先頭と末尾に一致する(マルチラインモード) |
(?s) | .を改行にマッチさせる |
(?x) | すべての空白文字類を無視し"#"と"\n"の間にあるものすべてをコメントとして扱う |
(?-∖#c) | オプションを解除する |
(?=p) | 後続するテキストは p にマッチしなければならない |
(?!p) | 後続するテキストは p にマッチしなければならない |
(?<= p) | 先行しているテキストは p にマッチしなければならない |
(?<!p) | 先行しているテキストは p にマッチしなければならない |
.,\,?,(,),{,},[,],^,$,*,+,が正規表現でエスケープしなければならない文字の完全リストである.例えば,文字通りのピリオドを書く際には"\\."を使い,文字通りのバックスラッシュを書く場合には"\\\\"を使う.
名前付きのサブパターンは,(subpatt)のように前後にカッコを置く.こうすると番号付きのサブパターンとなる.指定のサブパターンの番号は開きカッコを数え,カッコのはじめから始める.この場合,n 番目のサブパターンは\\n で参照することができる.規則の右辺では"$n"を使うことができる."$0"はマッチしたすべてのパターンを参照する:
正規表現
|
一般的な文字列パターン
|
説明
|
"abc" | "abc" | 文字通りの文字列 "abc" |
"." | Except["\n"] | 改行以外の任意の文字 |
"(?s)." | _ | 任意の文字 |
"(?s).+" | __ | 1つ以上の文字(最長マッチを行う) |
"(?s).+?" | Shortest[__] | 1つ以上の文字(最長マッチは行わない) |
"(?s).*" | ___ | 0以上の文字 |
".*" | Except["\n"]... | 0以上の文字(改行以外) |
"a?b" | "a" | ""~~"b"0あるいは1個の"a"が"b"の前にある("b","ab"等) |
"[abef]" | Characters["abef"] | "a","b","e","f"のいずれかの文字 |
"[abef]+" | Characters["abef"].. | 任意の数の"a","b","e","f"の文字 |
"[a-f]" | CharacterRange["a","f"] | "a"から"f"までの任意の文字 |
"[^abef]" | Except[Characters["abef"]] | "a","b","e","f"以外の任意の文字 |
"ab efg" | "ab" | "efg"文字列"ab"あるいは"efg"とのマッチ |
"(ab ef)gh" or "(?:ab ef)gh" | ("ab" "ef")~~"gh" | "ab"あるいは"ef"に"gh"が続くもの("abgh"か"efgh") |
"\\s" | WhitespaceCharacter | 任意の空白文字 |
"\\s+" | Whitespace | 1つ以上の空白文字 |
"(a b)\\1" | x:"a" | "b"~~x_"aa"か"bb"にマッチする |
"\\d" | DigitCharacter | 任意の数字 |
"\\D" | Except[DigitCharacter] | 任意の非数字 |
"\\d+" | DigitCharacter.. | 1つ以上の数字 |
"\\w" | WordCharacter "_" | 任意の数字,文字列,あるいは"_"記号 |
"[[:alpha:]]" | LetterCharacter | 任意の文字 |
"[^[:alpha:]]" | Except[LetterCharacter] | 任意の非文字 |
"^abf" or "\\Aabc" | StartOfString~~"abf" | 文字列の先頭にある文字列"abf" |
"(?m)^abf" | StartOfLine~~"abf" | 行頭にある文字列"abf" |
"wxz$" or "wxz\\z" | "wxz"~~EndOfString | 文字列の末尾にある文字列"wxz" |
"wxz\\Z" | "wxz"~~"\n"EndOfString | ""~~文字列の末尾あるいは改行の前にある文字列"wxz" |
一般的な文字列パターンでは直接使えない,正規表現の特別なコンストラクトもある.先読み/後読みや指定の長さの繰返し等がこれに当たる.これらはRegularExpressionオブジェクトを挿入することで,より大きな一般的文字列パターンに埋め込むことができる.
StringMatchQ
StringMatchQは,文字列全体が特定のパターンにマッチするかどうかを判定する:
(後読み互換性により)メタキャラクタの*や@をワイルドカードとして含むことができる点で,StringMatchQは特別である.*はShortest[___] (RegularExpression["(?s).*?"])に等しく,@はExcept[CharacterRange["A","Z"]] (RegularExpression["[^A-Z]"])に等しい.
ここでは可能なマッチを探しているだけなので,技術的にはShortestの見かけに違いがない点に注意のこと.
パターン中のサブパターンでマッチした文字列の一部分にアクセスする必要がある場合は.StringCasesを使用する.
StringFreeQ
StringFreeQは,ある文字列がパターンにマッチする部分文字列を含んでいるかどうかをチェックするのに使われる.マッチする部分文字列を抽出することはできない.抽出にはStringCasesを使う:
StringContainsQ
StringContainsQは,ある文字列がパターンにマッチする部分文字列を含んでいるかどうかをチェックするのに使われる.マッチする部分文字列を抽出することはできない.抽出にはStringCasesを使う:
StringStartsQ
StringStartsQは,ある文字列がパターンにマッチする部分文字列から始まるかどうかをチェックするのに使われる.マッチする部分文字列を抽出することはできない.抽出にはStringCasesを使う:
StringEndsQ
StringCases
StringCasesは,文字列中のパターンの生起を見付け,サブパターンを取り出し,結果を処理する一般的な目的関数である.
多くの文字列を効率よく処理するために第1引数として文字列のリストを与えることもできる(「効果的なマッチングのヒント」の説明も参照のこと):
Overlapsオプション
StringCases,StringPosition,StringCountのOverlapsオプションは,マッチを見付けた後のマッチャーの進め方を扱う.可能な設定値はFalse,True,Allの3つである.デフォルト値は,StringCasesとStringCountではFalse,StringPositionはTrueである.
StringPosition
StringCount
StringCountは,(StringPositionあるいはStringCasesで求められる)マッチする部分文字列の数を返す.これは,マッチが多く,すべての部分文字列を保存するためのメモリ量が問題となる場合に便利である:
StringReplace
StringReplaceは,与えられたパターンにマッチする部分文字列を代替するのに使われる
置換は文字列に限られない.結果が文字列でなければ,StringExpressionが返される:
StringReplaceList
StringReplaceListは,すべての可能な方法で単一の文字列置換が行われた文字列のリストを返す:
StringSplit
StringSplitは,パターンにマッチする区切りで文字列を分割するのに便利である.デフォルトでは,分割は一連の空白文字の位置で行われる:
Allを第3引数として指定することで,これらを含めることができる:
StartOfLineのように,位置にマッチするパターンで区切ることもできる.これは,結果に改行記号を残す:
はじめに
一般的な文字列パターンを加えることで,Wolfram言語は一般的かつ日常的なプログラミングタスクにおいてPerlやPythonのような言語に変わる強力なものになった.次は,Perlのシンタックスや文字列操作に馴染んでいる人のための,同様な機能をWolfram言語で使うための簡単な説明である.
Perlコンストラクト
| Wolfram言語関数 |
説明
|
m/ .../ | StringFreeQ または StringCases | 文字列を正規表現でマッチする.サブパターンを抽出することもある |
s/ .../ .../ | StringReplace | 正規表現にマッチする部分文字列を置換する |
split(...) | StringSplit | 正規表現にマッチする区切りの位置で文字列を分割する |
tr/ .../ .../ | StringReplace | 文字を他の文字で置換する |
/i | IgnoreCase->True または "(?i)" | 大文字小文字の区別をしない限定子 |
/s | "(?s)" | "."が改行を含むすべての文字にマッチするように強制する |
/x | "(?x)" | 空白文字類を無視し,正規表現による拡張されたコメントを許容する |
/m | "(?m)" | マルチラインモード("^"および"$"が行頭/行末に対応) |
m/.../
Wolfram言語では,StringCasesを使ってこれを行う:
Wolfram言語では,StringCasesを用いて同じことが簡単に行える:
s/.../.../
Perlの代替演算子はWolfram言語ではStringReplaceになる:
split(...)
PerlのコマンドはWolfram言語のStringSplitによく似ている:
パターン中のカッコをとらえたは,とらえられた部分文字列が結果に含まれるのだが,Wolfram言語ではStringSplitの第2引数として規則を使うことで簡単に行うことができる.Perlに比べ,Wolfram言語では,これらの部分文字列に簡単に関数を適用できる:
tr/.../.../
Perlのコマンドは,Wolfram言語ではStringReplaceと規則のリストを一緒に使うことでまねることができる.
次はWolfram言語でThreadを使った適切な規則を生成する:
Perlにおける文字領域は,Wolfram言語ではCharacterRangeを用いてまねられる:
パターンのハイライト
HTMLの解析
これはwww.google.comから取ったソースである:
金額の検索
この場合は組込みのパターンオブジェクトNumberStringを使うこともできる:
ファイル中のテキストの検索
StringExpressionとRegularExpression
Wolfram言語のシンタックスで書かれた文字列パターンは,即座に正規表現に変換され,ついでコンパイル,キャッシュされるので,正規表現のシンタックスを直接使うのに対してWolfram言語のシンタックスを使うことのオーバーヘッドはほとんどない.しかし例外として,多くの異なるパターンが何度か使われると明確なオーバーヘッドが起ることがある.
条件とパターンテスト
パターンにCondition (/;)あるいはPatternTest (?)文が含まれていると,マッチングの間にWolfram言語の評価装置が呼び出されるため,マッチングが遅くなる.上記のようなコンストラクトなしでパターンが書ける場合は,一般にこちらの方が速い:
ネストした量限定子を避ける
マッチに使われている非決定性有限オートマトン(NFA)アルゴリズムのために,ネストした量限定子(__,patt..あるいは正規表現でこれらに当たるもの等)を含んだパターンは非常に遅くなることがある.このようなパターンは,より効率のよいバージョンに「展開」することができる(詳しくはFriedl[2]を参照のこと).
関数を何度も呼び出すのを避ける
何らかのマッチを探して長いリストを検索しているなら,SelectやStringMatchQ等を使うよりも,リスト全体を文字列関数に一度にフィードした方が効率が上がる(前述の辞書の例を参照されたい).次の例は,10字からなっている文字列を2000個生成し,その中から"a"で始まり"ggg"という部分文字列を含んだものを探し出す:
また,StringCasesを使うこともできる.こちらも速い."a"が語頭にくるようにStartOfStringを使ってパターンを固定する必要がある(EndOfStringは,この例には過剰である):
通常の表現による検索を文字列検索に書き換える
文字列マッチングのアルゴリズムは,Wolfram言語が一般の式のマッチングに使うアルゴリズムとは異なるので(文字列マッチングは有限個のアルファベットと平坦な構造を仮定することができる等),通常の式のマッチングにおける問題を文字列マッチングの問題に置き換えて考えると都合がいいことがある.典型的な例として,記号の長いリストを__や___が何度か現れるパターンとマッチさせる例を考える.
Wolfram言語における文字列パターンのマッチングは,Philip Hazel[1]によるPCRE(Perl準拠の正規表現)ライブラリの上に構築されている.
次に正規表現がPCREによってコンパイルされ,コンパイルされたものは,将来的に同じパターンが再び現れたときに使うためにキャッシュされる.記号的な文字列パターンから正規表現への変換は1度しか行われない.
一般的な文字列パターンに埋め込まれた明示的なRegularExpressionオブジェクトは,(キャプチャしないカッコ"(?:...)"で挟まれた)最終的な正規表現に組み継がれるので,名前付きパターンを数えると予想と食い違うかもしれない.
PCREは現在のところ文字コード規格255を超えるあらかじめセットされた文字クラスはサポートしていないので,単語と文字のクラス(WordCharacter,LetterCharacter等)にはUnicodeの領域0-255にある文字コードのみが含まれる.このため,LetterCharacterおよび_?LetterQは文字コード規格255を超えた同等の結果は与えない.
PCREの同じような制限のため,(IgnoreCase->True等での)大文字小文字を区別しないマッチングはUnicodeの0-127の範囲にある文字(英語では通常"a"–"z"と"A"–"Z")にのみ適用される.
[1] Hazel, P. "PCRE—Perl Compatible Regular Expressions." (2004). www.pcre.org
[2] Friedl, J. E. F. Mastering Regular Expressions, 2nd ed. O'Reilly & Associates, 2002.