パターン・マッチング (?)
概要
ObjectScript のパターン・マッチング演算子は、文字列が 2 連続の大文字を含んでいるかどうかを判断します。
ObjectScript のパターン・マッチング演算子は、左オペランドの文字が、その右オペランドのパターンと正確に一致しているかどうかを判断します。この演算子はブーリアン値を返します。パターン・マッチング演算子は、パターンが左オペランドの文字パターンに一致した場合に True (1) の結果を返します。また、一致しなかった場合は False (0) の結果を返します。
以下の例は、文字列 ssn に有効な米国社会保障番号 (数字 3 桁、ハイフン、数字 2 桁、ハイフン、数字 4 桁) が含まれているかどうかをテストします。
SET ssn="123-45-6789"
SET match = ssn ? 3N1"-"2N1"-"4N
WRITE match
左オペランド (テスト値) と右オペランド (パターン) は、右オペランドの先頭の ? で区別されます。これら 2 つのオペランドは、以下の等価プログラムの例で示すように、1 つ以上の空白スペースで区切られる場合、もしくは空白スペースで区切られない場合もあります。
SET ssn="123-45-6789"
SET match = ssn?3N1"-"2N1"-"4N
WRITE match
? 演算子の後に空白が入ることはできません。パターン内の空白は引用符で囲まれた文字列内に置く必要があり、パターンの一部として解釈されます。
パターン・マッチング演算の一般的な形式は以下のとおりです。
operand?pattern
operand | パターンのテスト対象となる文字群である、文字列や数字として評価される式です。 |
pattern | ? 記号 (不一致テストの場合は ‘?) で始まるパターン・マッチング・シーケンスです。このパターン・シーケンスは、1 つ以上の pattern-elements (パターン要素) の列、あるいは 1 つ以上の pattern-elements の列として評価される間接参照のいずれかとなります。 |
pattern-element は以下のいずれかで構成されます。
-
repeat-count pattern-codes
-
repeat-count literal-string
-
repeat-count alternation
repeat-count | リピート・カウント — パターンの各インスタンスをマッチさせる具体的な回数です。repeat-count は、整数またはピリオド・ワイルドカード文字 (.) に評価できる文字です。任意の回数を指定するには、ピリオドを使用します。 |
pattern-codes | 1 つまたは複数のパターン・コード。複数のコードを指定した場合は、それらのコードのいずれかと一致するとパターンの条件が満たされます。 |
literal-string | 二重引用符で囲まれたリテラル文字列。 |
alternation | 一連の pattern-element。この pattern-element のいずれかを選択して、オペランド文字列のセグメントとのパターン・マッチングに使用します。これにより、パターン指定で論理 OR 機能が得られます。 |
特定の文字や文字列を比較する場合、二重引用符で囲んだリテラル文字列をパターンで使用します。他の状況では、ObjectScript が提供する特殊なパターン・コードを使用します。特定のパターン・コードに関連付けられる文字は、(ある程度の) ロケール依存となります。以下のテーブルは、使用可能なパターン・コードとその意味です。
Code | 意味 |
---|---|
A | 任意のアルファベットの大文字または小文字に一致。ロケールの 8 ビット文字セットは、アルファベット文字が何であるかを定義します。英語のロケール (Latin-1 文字セットに基づく) の場合、これには ASCII 値 65 ~ 90 (A ~ Z)、97 ~ 122 (a ~ z)、170、181、186、192 ~ 214、216 ~ 246、および 248 ~ 255 が含まれます。 |
C | 任意の ASCII 制御文字 (ASCII 値の 0 から 31 までと拡張 ASCII 値の 127 から 159 まで) と一致。 |
E | 出力不能文字、空白文字、および制御文字を含む任意の文字と一致。 |
L | 任意のアルファベットの小文字に一致。ロケールの 8 ビット文字セットは、小文字が何であるかを定義します。英語のロケール (Latin-1 文字セットに基づく) の場合、これには ASCII 値 97 ~ 122 (a ~ z)、170、181、186、223 ~ 246、および 248 ~ 255 が含まれます。 |
N | 10 個の ASCII 数字 (0 から 9、ASCII 48 から 57) のいずれとも一致。 |
P | 任意の句読点文字に一致。ロケールの文字セットは、拡張 (8 ビット) ASCII 文字セットに対して、句読点文字が何であるかを定義します。英語のロケール (Latin-1 文字セットに基づく) の場合、これには ASCII 値 32 ~ 47、58 ~ 64、91 ~ 96、123 ~ 126、160 ~ 169、171 ~ 177、180、182 ~ 184、187、191、215、および 247 が含まれます。 |
U | 任意のアルファベットの大文字に一致。ロケールの 8 ビット文字セットは、大文字が何であるかを定義します。英語のロケール (Latin-1 文字セットに基づく) の場合、これには ASCII 値 65 ~ 90 (A ~ Z)、192 ~ 214、および 216 ~ 222 が含まれます。 |
R B M |
キリル 8 ビット・アルファベット文字のマッピングに一致。R は任意のキリル文字 (ASCII 値の 192 から 255 まで) と一致します。B は大文字のキリル文字 (ASCII 値の 192 から 223 まで) と一致します。M は小文字のキリル文字 (ASCII 値の 224 から 255 まで) と一致します。これらのパターン・コードは、Russian 8 ビット Windows ロケール (ruw8) のみで意味を持ちます。他のロケールでは、実行には成功しますが、いずれの文字とも一致しません。 |
ZFWCHARZ | 日本語の全角文字セットのいずれの文字とも一致。ZFWCHARZ は、漢字などの全角文字や、一部のターミナル・エミュレータによって表示されたときに二重セルを占有する多くの漢字以外の文字に一致します。また、ZFWCHARZ は JIS2004 標準で定義された 303 のサロゲート・ペア文字とも一致して、各サロゲート・ペアを単一文字として扱います。例えば、サロゲート・ペア文字 $WC(131083) は、?1ZFWCHARZ に一致します。このパターン・マッチング・コードには、日本語ロケールが必要となります。詳細は、"$ZZENKAKU" 関数を参照してください。 |
ZHWKATAZ | 日本語の半角かな文字セットのいずれの文字とも一致。これらは、Unicode 値 65377 (FF61) ~ 65439 (FF9F) までです。このパターン・マッチング・コードには、日本語ロケールが必要となります。詳細は、"$ZZENKAKU" 関数を参照してください。 |
パターン・コードは大文字と小文字を区別しません。大文字と小文字いずれも指定できます。例えば、?5N と ?5n は等価です。複数のパターン・コードを指定して、特定の文字または文字列に一致させることができます。例えば、?1NU は数字または大文字のいずれかに一致します。
ASCII 文字セットは、制約の多い 7 ビット文字セットではなく拡張された 8 ビット文字セットを表します。
二重引用符文字と一致するパターンは、異なる NLS ロケールを使用して InterSystems IRIS 実装からデータが提供されている場合に特に、不整合な結果を生じる場合があります。まっすぐな二重引用符文字 ($CHAR(34) = ") は、句読点文字として照合されます。方向性のある二重引用符文字 (巻いている引用符) は、句読点文字として照合されません。8 ビットの方向性のある二重引用符文字 ($CHAR(147) = “ と $CHAR(148) = ”) は、制御文字として照合されます。Unicode の方向性のある二重引用符文字 ($CHAR(8220) = “ と $CHAR(8221) = ”) は、句読点文字としても、制御文字としても照合されません。
パターン・マッチング演算子は、包含関係演算子 ([) とは異なります。包含関係演算子は、左辺のオペランドの部分文字列が右辺のオペランドと一致する場合も、True (1) を返します。また、包含関係式は、パターン・マッチング演算子で使用できる一連のオプションを提供しません。包含関係式では、単一の文字列のみ右辺のオペランドで使用できます。特殊コードは使用できません。
例えば、変数 var2 に値 "abc" が含まれているとします。以下のパターン・マッチ式を考えてみます。
SET match = var2?2L
var2 は、2 つではなく 3 つの小文字を持っているため、match は False (0) の結果を返します。
以下に、基本的なパターン・マッチングの例を示します。
PatternMatchTest
SET var = "O"
WRITE "Is the letter O",!
WRITE "...an alphabetic character? "
WRITE var?1A,!
WRITE "...a numeric character? "
WRITE var?1N,!
WRITE "...an alphabetic or ",!," a numeric character? "
WRITE var?1AN,!
WRITE "...an alphabetic or ",!," a ZENKAKU Kanji character? "
WRITE var?1AZFWCHARZ,!
WRITE "...a numeric or ",!," a HANKAKU Kana character? "
WRITE var?1ZHWKATAZN
以下の項目を指定して、パターン・コードの範囲を拡張できます。
パターン・カウントの指定
以下の形式で、目的のオペランドで パターン が繰り返し発生できる回数の範囲を定義します。
n.n
1 番目の n は範囲の下限を、2 番目の n は上限を定義します。
以下の例では、変数 var3 に文字列 "AB" の複数のコピーが含まれていて、その他の文字は含まれていないものとします。1.4 は "AB" が 1 ~ 4 回出現すると認識されていることを示します。
SET match = var3?1.4"AB"
var3 =ABABAB の場合、この式は、var3 に "AB" が 3 つしか含まれていない場合でも、True (1) の結果を返します。
別の例として、以下の式を考えてみます。
SET match = var4?1.6A
この式は、var4 に 1 個から 6 個までの英文字が含まれているかどうかをチェックします。var4 に英文字がまったく含まれていないか、7 文字以上の英文字が含まれているか、または英文字以外の文字が含まれている場合、False (0) の結果を返します。
どちらか一方の n を省略すると、ObjectScript は既定値を提供します。1 番目の n の既定値はゼロ (0) です。2 番目の n の既定値は任意の値です。以下の例を確認してください。
SET match = var5?.E1"AB".E
この例は、var5 に、パターン文字列 "AB" が少なくとも 1 つ含まれている限り、True (1) を返します。
複数パターンの指定
複数パターンを定義するには、任意の長さで n とパターンを組み合わせます。以下の例を確認してください。
SET match = date?2N1"/"2N1"/"2N
この式は、mm/dd/yy 形式で日付値をチェックします。文字列 "4/27/98" の場合、月の値が 1 桁なので False (0) を返します。1 桁の月と 2 桁の月の両方を検出するには、以下のように変更します。
SET match = date?1.2N1"/"2N1"/"2N
1 番目のパターン・マッチング (1.2N) は、1 桁または 2 桁の数字を受け取ります。前述のように、繰り返し回数の範囲を定義するため、オプションの小数点 (.) を使用します。
組み合わせパターンの指定
以下の形式を使用して、組み合わせパターンを定義します。
Pattern1Pattern2
パターンの組み合わせで、pattern1 に pattern2 が続く配列との比較で、目的のオペランドをチェックします。例えば、以下の式を考えてみます。
SET match = value?3N.4L
この式は、3 桁の数字の後ろに、0 から 4 つの小文字の英字が続いているかどうかのパターンをチェックします。目的のオペランドにパターンの組み合わせと同じものが 1 つ含まれている場合にのみ True (1) を返します。例えば、文字列 "345g" と "345gfij" は一致しますが、"345gfijhkbc" と "345gfij276hkbc" は一致しません。
不確定パターンの指定
以下の形式を使用して、不確定パターンを指定します。
.pattern
不確定パターンを使用して、目的のオペランドは、pattern の繰り返しをチェックします。繰り返しの数は (ゼロ回を含め) 指定されません。例えば、以下の式を考えてみます。
SET match = value?.N
この式は、目的のオペランドがゼロもしくは 1 つ以上の数字を含み、その他のタイプの文字を含まない場合、True (1) を返します。
交互パターンの指定 (論理 OR)
交互パターンを使用すると、指定した複数のパターン列のいずれかとオペランドが一致するかどうかをテストできます。これにより、パターン・マッチングで論理 OR 機能が得られます。
交互パターンの構文は、以下のとおりです。
( pattern-element sequence {, pattern-element sequence }...)
したがって、以下のパターンは、val に文字 A が 1 回出現する、あるいは文字 B が 1 回出現する場合に True (1) を返します。
SET match = value?1(1"A",1"B")
交互パターンは、以下のパターン・マッチング式のように入れ子にできます。
SET match = value?.(.(1A,1N),1P)
例えば、電話番号の妥当性を検証する場合、少なくとも、電話番号は、3 桁目と 4 桁目の間にハイフン (-) のある 7 桁の番号である必要があります。以下に例を示します。
nnn-nnnn
また、電話番号に 3 桁の市外局番がある場合、括弧で囲むか、ハイフンで残りの番号から区別する必要があります。以下に例を示します。
(nnn) nnn-nnnn
nnn-nnn-nnnn
以下のパターン・マッチング式は、電話番号の 3 つの有効な形式を示します。
SET match = phone?3N1"-"4N
SET match = phone?3N1"-"3N1"-"4N
SET match = phone?1"("3N1") "3N1"-"4N
交互パターンを使用しない場合には、次の複合ブーリアン式が、あらゆる形式の電話番号の妥当性を確認するために必要となります。
SET match =
(
(phone?3N1"-"4N) ||
(phone?3N1"-"3N1"-"4N) ||
(phone?1"("3N1") "3N1"-"4N)
)
交互パターンを使用する場合、電話番号の妥当性を検証するために、以下の単一のパターンが必要です。
SET match = phone?.1(1"("3N1") ",3N1"-")3N1"-"4N
この例の交互パターンでは、電話番号の市外局番部分を、1"("3N1")" または 3N1"-" のいずれかで表現することできます。0 から 1 の交互カウント範囲は、オペランド phone が、0 または 1 のエリア・コードを持てることを示します。
1 より大きい反復カウントを持つ交互パターンは、使用できるパターンの組み合わせを多く生成できます。以下の交互パターンは、例で示されている文字列と一致する以外に、26 とおりの 3 文字の文字列と一致します。
SET match = "CAT"?3(1"C",1"A",1"T")
交互パターンでは、不確定パターンの中で不確定パターンを入れ子にできます。例えば、.(.A,.N) は、入れ子にした不確定パターンを含む交互パターンです。このような構造は、適正な長さの文字列に対する演算であっても、実行時間が極端に長くなる可能性があることに注意してください。Ctrl-C を押すことで、実行を停止できます。アプリケーションで不確定パターンを入れ子にする必要があるものの、実行時間がかかりすぎる場合は、$MATCH を使用して正規表現 (Regex) マッチングを試してみます。その方が効率的になることがあります。
不完全パターンの使用法
パターン・マッチングにより、文字列の一部しか一致しない場合、False (0) の結果を返します。つまり、パターンがすべて比較された後は、文字列が残っていてはならないことを示します。以下の式は、パターンの最後の R が一致しないため、False (0) を返します。
SET match = "RAW BAR"?.U1P2U
パターンの複数解釈
オペランドを比較する際に、1 つのパターンに複数の解釈が可能な場合があります。例えば、以下の式は 2 とおりの解釈ができます。
SET match = "/////A#####B$$$$$"?.E1U.E
-
最初の .E が部分文字列の ///// と一致し、1U は A と一致し、2番目の .E は部分文字列の #####B$$$$$ と一致します。
-
最初の .E が部分文字列は /////A##### と、1U は B と一致し、2番目の .E は部分文字列の .E と一致します。
少なくとも式の 1 つの解釈が True (1) である場合、式の値は True となります。
非マッチ演算
非マッチ演算は、パターン・マッチング演算子と共に否定演算子 ( ' ) を使用して記述できます。
operand'?pattern
非マッチ演算は、パターン・マッチングの真偽値を反転します。オペランドの文字がパターンと一致しない場合、非マッチ演算は True (1) を返します。パターンがオペランドの文字のすべてに一致する場合、非マッチ演算は False (0) を返します。
以下の例では、非マッチ演算が使用されています。
WRITE !,"abc" ?3L
WRITE !,"abc" '?3L
WRITE !,"abc" ?3N
WRITE !,"abc" '?3N
WRITE !,"abc" '?3E
パターンの複雑さ
一部の複雑なパターンでは、適正な長さの文字列に対する演算であっても、実行時間が極端に長くなる場合があります。特に交互パターンと不確定パターンの組み合わせは、実行時に問題を引き起こす可能性があります。パターン・マッチング文を使用したプログラムの実行に、予想より大幅に時間がかかっている場合、Ctrl-C を使用して <INTERRUPT> エラーで実行を中止し、使用しているパターンを簡潔にします。パターンを簡潔にできない場合は、$MATCH による Regex マッチングを試します。パターン・マッチングよりも効率的になることがあります。
複数の変更と不明確なパターンによるパターン・マッチは、長い文字列に適用される場合、多くのレベルをシステム・スタックに繰り返す場合があります。きわめてまれに、この繰り返しが数千回程度にまで増加し、スタックのオーバーフローおよびプロセスのクラッシュが発生することがあります。このような極端な状況が発生した場合、InterSystems IRIS は、現在のプロセスのクラッシュの危険を冒すよりはむしろ、<COMPLEX PATTERN> エラーを発行します。このような場合は、パターンを簡潔にするか、元の文字列のより短い部分にパターンを適用することをお勧めします。
正規表現に関する注記
ObjectScript では、多くのソフトウェア・ベンダよりサポートされる (バリアントを用いた) パターン・マッチ構文である正規表現をサポートします。正規表現は、$LOCATE および $MATCH 関数と %Regex.MatcherOpens in a new tab クラスのメソッドで使用できます。
これらのパターン・マッチング・システムは完全に別個のものです。それぞれのパターン・マッチング・システムはその独自のコンテキストでのみ使用できます。ただし、以下の例で示すように、論理 AND および OR 構文を使用して、異なるパターン・マッチング・システムからパターン・マッチング・テストを組み合わせることは可能です。
SET var = "abcDEf"
IF (var ?.e2U.e) && $MATCH(var, "^.{3,7}") { WRITE "It's a match!"}
ELSE { WRITE "No match"}
ObjectScript のパターンは、文字列が 2 連続の大文字を含んでいるかどうかを判断します。正規表現のパターンは、文字列が 3 ~ 7 文字かどうかを判断します。