1

正規表現を使用して一部のデータを「解析」しようとしてきましたが、近づいているように感じますが、すべてを家に持ち帰ることができないようです。
通常、解析が必要なデータは次のようになります<param>: <value>\n。パラメータの数は、値と同様に変更できます。それでも、ここに例があります:

FooID: 123456
名前:チャック
日時: 2013 年 1 月 2 日 01:23:45
内部 ID: 789654
ユーザーメッセージ: こんにちは。
これは nillable ですが、非常に長くなる可能性があります。テキストは複数の行にまたがることができます
また、任意の数の \n で開始できます。空にすることもできます。
さらに悪いことに、これにはコロンを含めることができます (ただし、`\` を使用して_"エスケープ"_されます)、さらには基本的なマークアップです!

このテキストをオブジェクトにプッシュするために、この小さな表現をまとめました

if (preg_match_all('/^([^:\n\\]+):\s*(.+)/m', $this->structuredMessage, $data))
{
    $data = array_combine($data[1], $data[2]);
    //$data is assoc array FooID => 123456, Name => Chuck, ...
    $report = new Report($data);
}

User Messageさて、これはビットを除いてほとんどの場合問題なく動作します:.新しい行に一致しません。sフラグを使用すると、2 番目のグループはFooID:文字列の最後まですべてに一致するためです。
そのためには、汚い回避策を使用する必要があります。

$msg = explode(end($data[1], $string);
$data[2][count($data[2])-1] = array_pop($msg);

いくつかのテストの後、1 つまたは 2 つのパラメーターが入力されていない場合があることがわかりました (たとえば、InternalIDが空である可能性があります)。その場合、私の式は失敗しませんが、結果は次のようになります。

    [1] => 配列
        (
            [0] => FooID
            [1] => 名前
            [2] =>いつ
            [3] => 内部 ID
        )

    [2] => 配列
        (
            [0] => 123465
            [1] => チャック
            [2] => 2013 年 1 月 2 日 01:23:45
            [3] => ユーザーのコメント: こんにちは。
        )

いろいろな表現を試した結果、以下のようになりました。

/^([^:\n\\]++)\s{0,}:(.*+)(?!^[^:\n\\]++\s{0,}:)/m
//or:
/^([^:\n\\]+)\s{0,}:(.*)(?!^[^:\\\n]+\s{0,}:)/m

2 番目のバージョンは少し遅くなります。
これで私が抱えていた問題は解決しましたInternalID: <void>が、それでも最後の障害が残っていますUser Message: <multi-line>。フラグを使用してsも、私の表現 ATM ではうまくいきません。
私はこれしか考えられません:

^([^:\n\\]++)\s{0,}:((\n(?![^\n:\\]++\s{0,}:)|.)*+)

少なくとも私の目には、これは複雑すぎて唯一の選択肢にはなりません。アイデア、提案、リンク、...何でも大歓迎です

4

4 に答える 4

1

次の正規表現は機能するはずですが、これが適切なツールであるかどうかはわかりません。

preg_match_all(
    '%^            # Start of line
    ([^:]*)        # Match anything until a colon, capture in group 1
    :\s*           # Match a colon plus optional whitespace
    (              # Match and capture in group 2:
     (?:           # Start of non-capturing group (used for alternation)
      .*$          #  Either match the rest of the line
      (?=          #  only if one of the following follows here:
       \Z          #  The end of the string
      |            #  or
       \r?\n       #  a newline
       [^:\n\\\\]* #  followed by anything except colon, backslash or newline
       :           #  then a colon
      )            #  End of lookahead
     |             # or match
      (?:          #  Start of non-capturing group (used for alternation/repetition)
       [^:\\\\]    #  Either match a character except colon or backslash
      |            #  or
       \\\\.       #  match any escaped character
      )*           #  Repeat as needed (end of inner non-capturing group)
     )             # End of outer non-capturing group
    )              # End of capturing group 2
    $              # Match the end of the line%mx', 
    $subject, $result, PREG_PATTERN_ORDER);

regex101でライブを参照してください。

于 2013-07-10T13:51:31.140 に答える
1

私はPHPにかなり慣れていないので、これは完全にうまくいかないかもしれませんが、次のようなものを使用できるかもしれません

$data = <<<EOT
FooID: 123456
Name: Chuck
When: 01/02/2013 01:23:45
InternalID: 789654
User Message: Hello,
this is nillable, but can be quite long. Text can be spread out over many     lines
And can start with any number of \n's. It can be empty, too
EOT;

if ($key = preg_match_all('~^[^:\n]+?:~m', $data, $match)) {
    $val = explode('¬', preg_filter('~^[^:\n]+?:~m', '¬', $data));

    array_shift($val);

    $res = array_combine($match[0], $val);
}

print_r($res);

収量

Array
(
    [FooID:] =>  123456
    [Name:] =>  Chuck
    [When:] =>  01/02/2013 01:23:45
    [InternalID:] =>  789654
    [User Message:] =>  Hello,
this is nillable, but can be quite long. Text can be spread out over many     lines
And can start with any number of 
's. It can be empty, too
)
于 2013-07-10T13:42:53.427 に答える
0

だから、トリッキーを使って私が思いついたのは次のpreg_replace_callback()とおりです。

$string ='FooID: 123456
Name: Chuck
When: 01/02/2013 01:23:45
InternalID: 789654
User Message: Hello,
this is nillable, but can be quite long. Text can be spread out over many lines
And can start with any number of \n\'s. It can be empty, too
Yellow:cool';

$array = array();
preg_replace_callback('#^(.*?):(.*)|.*$#m', function($m)use(&$array){
    static $last_key = ''; // We are going to use this as a reference
    if(isset($m[1])){// If there is a normal match (key : value)
        $array[$m[1]] = $m[2]; // Then add to array
        $last_key = $m[1]; // define the new last key
    }else{ // else
        $array[$last_key] .= PHP_EOL . $m[0]; // add the whole line to the last entry
    }
}, $string); // Anonymous function used thus PHP 5.3+ is required
print_r($array); // print

オンラインデモ

欠点PHP_EOLOS関連の改行を追加するために使用しています。

于 2013-07-10T12:51:43.050 に答える