興味深い質問です。そして、phant0m の回答は非常に教育的です! (パーサーを理解している場合は使用する必要があります)。
正規表現のみを使用してこれを行う場合、次のソリューションは、JavaScript を使用して、任意にネストされた論理ステートメントを正しく検証します。
ルール/前提:
- 有効なステートメントは、数字、括弧、スペース、
AND
論理演算子、および論理演算子のみで構成されOR
ます。
- ステートメントには、論理演算子で区切られた少なくとも 2 つの「トークン」が含まれている必要があります。各トークンは「数値」または「括弧で囲まれた単位」です。
+
「数値」トークンは、オプションの記号 ( または のいずれか)の直前に 1 つ以上の 10 進数がある数値整数です-
。
- 「括弧で囲まれた単位」トークンは、論理演算子で区切られた 2 つ以上のトークンであり、対応する開き括弧と閉じ括弧で囲まれています。
- ステートメント全体に 3 つ以上のトークンを含めることができますが、すべてのトークンは同じ単一の演算子で区切る必要があります。またはのいずれ
AND
かOR
。
- 括弧で囲まれた各ユニットには 3 つ以上のトークンを含めることができますが、すべてのトークンは同じ単一の演算子で区切る必要があります。またはのいずれ
AND
かOR
。
- 任意の要素 (括弧、数値、および論理演算子) の間に任意の量の空白を使用できますが、数値と論理演算子の間には少なくとも 1 つのスペースが必要です。
AND
and論理演算子は、大文字とOR
小文字を区別しません。
有効な論理ステートメントの例:
"1 AND 2"
"1 AND 2 AND 3"
"1 OR 2"
"-10 AND -20"
"100 AND +200 AND -300"
"1 AND (2 OR 3)"
"1 AND (2 OR 3) AND 4"
"1 OR ((2 AND 3 AND 4) OR (5 OR 6 OR 7))"
"( 1 and 2 ) AND (1 AND 2)"
無効な論理ステートメントの例:
"1x" // Invalid character.
"1 AND" // Missing token.
"1 AND 2 OR 3" // Mixed logical operators.
"(1" // Unbalanced parens.
"(((1 AND 2)))" // Too many parens.
"(1 AND) (2)" // Missing token.
"1" // Missing logical operator and second number
"1OR2OR3OR4" // Missing spaces between numbers and operators.
"(1) AND (2)" // Invalid parentheses.
正規表現ソリューション:
この問題は、ネストされた括弧で囲まれた構造を一致させる必要があり、JavaScript 正規表現エンジンは再帰式をサポートしていないため、この問題は単一の正規表現を使用して 1 回で解決することはできません。ただし、この問題は 2 つの部分に単純化でき、それぞれを1 つの JavaScript 正規表現で解決できます。最初の正規表現は最も内側の括弧で囲まれたユニットに一致し、2 番目の正規表現は簡略化された論理ステートメント (括弧を持たない) を検証します。
正規表現 #1: 最も内側の括弧で囲まれたユニットに一致します。
次の正規表現は、2 つ以上の数値トークンで構成される括弧で囲まれた 1 つの単位に一致します。ここで、数値はすべて、AND
またはOR
数値と論理演算子の間に少なくとも 1 つのスペースで区切られます。正規表現は、PHP フリースペース モードの構文で読みやすいように完全にコメント化され、フォーマットされています。
$re_paren = '/
# Match innermost "parenthesized unit".
\( # Start of innermost paren group.
\s* # Optional whitespace.
[+-]?\d+ # First number token (required).
(?: # ANDs or ORs (required).
(?: # Either multiple AND separated values.
\s+ # Required whitespace.
AND # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number.
)+ # multiple AND separated values.
| (?: # Or multiple OR separated values.
\s+ # Required whitespace.
OR # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number token.
)+ # multiple OR separated values.
) # ANDs or ORs (required).
\s* # Optional whitespace.
\) # End of innermost paren group.
/ix';
正規表現 #2: 簡略化された論理ステートメントを検証します。
以下は、簡略化された論理ステートメント (数字と論理演算子のみを持ち、括弧がない) を検証する (境界アンカーを除いてほぼ同じ) 正規表現です。これは、コメント付きのフリースペース モード (PHP) 構文です。
$re_valid = '/
# Validate simple logical statement (no parens).
^ # Anchor to start of string.
\s* # Optional whitespace.
[+-]?\d+ # First number token (required).
(?: # ANDs or ORs (required).
(?: # Either multiple AND separated values.
\s+ # Required whitespace.
AND # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number.
)+ # multiple AND separated values.
| (?: # Or multiple OR separated values.
\s+ # Required whitespace.
OR # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number token.
)+ # multiple OR separated values.
) # ANDs or ORs (required).
\s* # Optional whitespace.
$ # Anchor to end of string.
/ix';
これら 2 つの正規表現は、境界アンカーを除いて同一であることに注意してください。
JavaScript ソリューション:
次のテスト済みの JavaScript 関数は、上記の 2 つの正規表現を使用して問題を解決します。
function isValidLogicalStatement(text) {
var re_paren = /\(\s*[+-]?\d+(?:(?:\s+AND\s+[+-]?\d+)+|(?:\s+OR\s+[+-]?\d+)+)\s*\)/ig;
var re_valid = /^\s*[+-]?\d+(?:(?:\s+AND\s+[+-]?\d+)+|(?:\s+OR\s+[+-]?\d+)+)\s*$/ig;
// Iterate from the inside out.
while (text.search(re_paren) !== -1) {
// Replace innermost parenthesized units with integer.
text = text.replace(re_paren, "0");
}
if (text.search(re_valid) === 0) return true;
return false;
}
この関数は、反復手法を使用して、最初に最も内側の括弧で囲まれたユニットを照合して置き換え、それぞれを単一の数字トークンに置き換えてから、結果のステートメント (括弧なし) が有効かどうかを確認します。
補遺: 2012-11-06
この回答へのコメントで、OPは、数字と演算子の間にスペースが必要であり、数字または括弧で囲まれた単位は単独で立つことはできないと述べています。これらの追加要件を念頭に置いて、上記の回答を更新しました。