0

我试图在不使用解析器的情况下从 CSV 文件中分离一行,我需要做的就是使用 php 根据逗号拆分字符串。如果输入中没有逗号,这本身就相当容易,但事实并非如此。我想忽略用双引号括起来的逗号。

完全无视最后一句话,我决定把问题本身改成如下:

我想根据前面没有双引号或分散的双引号对的逗号来拆分字符串。

例子:

text,"some,"chars,chars"more,""text",
    *     x      *          x       *

其中 * 是匹配项,而 x 不是。

这是否超出了正则表达式的能力,如果没有,是否有可以处理这种输入的正则表达式?

4

2 回答 2

1

我确信这可以写得更好,但这里有一个适用于您的情况的变体:

 preg_match_all('/
     \s* ((?: (?=.|(?<=,)$) [^",]* | "(?: ""|[^"]* )+" )+) \s* (?:,|$) /xms',
     $line, $matches
 )
 and print_r($matches[1]);

但它不遵守其他典型的 CSV 规则。我通常希望\"成为其中的转义双引号。并且混合引用和未引用的子字符串也非常不标准。而且它缺乏任何形式的验证,因此只会忽略任何最后的报价——无论是否正确配对。

对于您的测试字符串:

        [0] => text
        [1] => "some,"chars
        [2] => chars"more,""text"
        [3] => 
于 2012-01-17T23:19:57.507 回答
1

如果您的 CSV 文件是正确的(每个字段以“开头和结尾”或不包含“”,那么您可以使用递归函数解析字符串,如下所示:

$csvString = 'zero,"o,ne",two,"thr,ee"';

function parseCsv($string, &$result)
{
    $regex = '/^((".*")|([^"].*))(,(.*))?$/U';
    $matches = array();
    preg_match($regex, $string, $matches);
    $result[] = $matches[1];
    if(isset($matches[5]))
    {
        parseCsv($matches[5], $result);
    }
}

$result = array();
parseCsv($csvString, $result);

var_dump($result);

请注意,这尚未使用包含(转义)引号的带引号的字符串进行测试。它还保留引用字符串周围的引号。

上述函数的结果是

array
  0 => string 'zero' (length=4)
  1 => string '"o,ne"' (length=6)
  2 => string 'two' (length=3)
  3 => string '"thr,ee"' (length=8)
于 2012-01-17T23:25:14.760 回答