52

文字列を区切り文字で分割するにはどうすればよいですか? たとえば、次の文字列があります。

1|2\|2|3\\|4\\\|4

区切り文字は|で、エスケープされた区切り文字は\|です。さらに、エスケープされたバックスラッシュを無視したいので、 in\\||まだ区切り文字です。

したがって、上記の文字列では、結果は次のようになります。

[0] => 1
[1] => 2\|2
[2] => 3\\
[3] => 4\\\|4
4

5 に答える 5

107

ダーク マジックを使用します。

$array = preg_split('~\\\\.(*SKIP)(*FAIL)|\|~s', $string);

\\\\.バックスラッシュとそれに続く文字に一致し、(*SKIP)(*FAIL)それをスキップし\|て区切り文字に一致します。

于 2011-06-05T15:20:46.003 に答える
11

の代わりにsplit(...)、レキシカルトークナイザーのように動作するある種の「スキャン」機能を使用する方がIMOより直感的です。PHPでは、それがpreg_match_all関数になります。あなたは単にあなたが一致したいと言います:

  1. \または以外のもの|
  2. またはの\後に\またはが続く|
  3. #1または#2を少なくとも1回繰り返す

次のデモ:

$input = "1|2\\|2|3\\\\|4\\\\\\|4";
echo $input . "\n\n";
preg_match_all('/(?:\\\\.|[^\\\\|])+/', $input, $parts);
print_r($parts[0]);

印刷されます:

1|2\|2|3\\|4\\\|4

Array
(
    [0] => 1
    [1] => 2\|2
    [2] => 3\\
    [3] => 4\\\|4
)
于 2011-10-02T18:06:53.533 に答える
4

最近、私は解決策を考案しました:

$array = preg_split('~ ((?<!\\\\)|(?<=[^\\\\](\\\\\\\\)+)) \| ~x', $string);

しかし、黒魔術のソリューションは依然として 3 倍高速です。

于 2011-06-06T05:52:08.753 に答える
4

将来の読者のために、ここに普遍的な解決策があります。これは、次のような NikiC のアイデアに基づいてい(*SKIP)(*FAIL)ます。

function split_escaped($delimiter, $escaper, $text)
{
    $d = preg_quote($delimiter, "~");
    $e = preg_quote($escaper, "~");
    $tokens = preg_split(
        '~' . $e . '(' . $e . '|' . $d . ')(*SKIP)(*FAIL)|' . $d . '~',
        $text
    );
    $escaperReplacement = str_replace(['\\', '$'], ['\\\\', '\\$'], $escaper);
    $delimiterReplacement = str_replace(['\\', '$'], ['\\\\', '\\$'], $delimiter);
    return preg_replace(
        ['~' . $e . $e . '~', '~' . $e . $d . '~'],
        [$escaperReplacement, $delimiterReplacement],
        $tokens
    );
}

試してみてください:

// the base situation:
$text = "asdf\\,fds\\,ddf,\\\\,f\\,,dd";
$delimiter = ",";
$escaper = "\\";
print_r(split_escaped($delimiter, $escaper, $text));

// other signs:
$text = "dk!%fj%slak!%df!!jlskj%%dfl%isr%!%%jlf";
$delimiter = "%";
$escaper = "!";
print_r(split_escaped($delimiter, $escaper, $text));

// delimiter with multiple characters:
$text = "aksd()jflaksd())jflkas(('()j()fkl'()()as()d('')jf";
$delimiter = "()";
$escaper = "'";
print_r(split_escaped($delimiter, $escaper, $text));

// escaper is same as delimiter:
$text = "asfl''asjf'lkas'''jfkl''d'jsl";
$delimiter = "'";
$escaper = "'";
print_r(split_escaped($delimiter, $escaper, $text));

出力:

Array
(
    [0] => asdf,fds,ddf
    [1] => \
    [2] => f,
    [3] => dd
)
Array
(
    [0] => dk%fj
    [1] => slak%df!jlskj
    [2] => 
    [3] => dfl
    [4] => isr
    [5] => %
    [6] => jlf
    )
Array
(
    [0] => aksd
    [1] => jflaksd
    [2] => )jfl'kas((()j
    [3] => fkl()
    [4] => as
    [5] => d(')jf
)
Array
(
    [0] => asfl'asjf
    [1] => lkas'
    [2] => jfkl'd
    [3] => jsl
)

注:理論レベルの問題がありimplode('::', ['a:', ':b'])implode('::', ['a', '', 'b'])結果は同じ文字列:になり'a::::b'ます。内破も興味深い問題です。

于 2014-11-25T19:59:48.803 に答える