【问题标题】:REGEX: Splitting by commas that are not in single quotes, allowing for escaped quotes正则表达式:用不在单引号中的逗号分隔,允许转义引号
【发布时间】:2010-11-22 14:09:28
【问题描述】:

我正在寻找一个在 PHP 5 中使用 preg_match_all 的正则表达式,它允许我用逗号分割字符串,只要逗号不存在于单引号内,允许转义单引号。示例数据是:

(some_array, 'some, string goes here','another_string','this string may contain "double quotes" but, it can\'t split, on escaped single quotes', anonquotedstring, 83448545, 1210597346 + '000', 1241722133 + '000')

这应该会产生如下所示的匹配:

(some_array

'some, string goes here'

'another_string'

'this string may contain "double quotes" but, it can\'t split, on escaped single quotes'

 anonquotedstring

 83448545

 1210597346 + '000'

 1241722133 + '000')

我尝试了很多很多正则表达式...我当前的正则表达式看起来像这样,尽管它没有 100% 正确匹配。 (它仍然在单引号内分割一些逗号。)

"/'(.*?)(?<!(?<!\\\)\\\)'|[^,]+/"

【问题讨论】:

  • 这个可以做到,但比大多数人想象的要难;看起来你现在已经感受到了困难。在 PHP 中真的没有库函数来处理这个问题吗? Perl中有。如果到那时你还没有得到一个好的答案,我可能会尝试稍后为你整理正则表达式。

标签: php regex


【解决方案1】:

你试过str_getcsv吗?无需正则表达式,它就可以完全满足您的需求。

$result = str_getcsv($str, ",", "'");

您甚至可以在早于 5.3 的 PHP 版本中实现此方法,使用文档中来自 a comment 的这个 sn-p 映射到 fgetcsv:

if (!function_exists('str_getcsv')) {

    function str_getcsv($input, $delimiter = ',', $enclosure = '"', $escape = null, $eol = null) {
        $temp = fopen("php://memory", "rw");
        fwrite($temp, $input);
        fseek($temp, 0);
        $r = fgetcsv($temp, 4096, $delimiter, $enclosure);
        fclose($temp);
        return $r;
    }

}

【讨论】:

  • 此解决方案有效。 str_getcsv 不是一个有效的函数,因为我没有运行 PHP 5.3+
  • 不幸的是 str_getcsv 对单引号内逗号的处理方式不一致:3v4l.org/Ubk1U
  • @greggles:我不知道任何允许单引号作为字符串附件的 CSV 解释。它也不在 RFC 4180 中,但 PHP 确实允许您根据文档将附件设置为单引号。
  • 好点,@AndyE。我的情况碰巧包括 ' 作为现场外壳,但我不知道为什么。以后我一定会考虑搬到“”。
【解决方案2】:

从 PHP 5.3 开始,您可以使用 str_getcsv 来避免这种痛苦

 $data=str_getcsv($input, ",", "'");

举个例子……

$input=<<<STR
(some_array, 'some, string goes here','another_string','this string may contain "double quotes" but it can\'t split on escaped single quotes', anonquotedstring, 83448545, 1210597346 + '000', 1241722133 + '000')
STR;

$data=str_getcsv($input, ",", "'");
print_r($data);

输出这个

Array
(
    [0] => (some_array
    [1] => some, string goes here
    [2] => another_string
    [3] => this string may contain "double quotes" but it can\'t split on escaped single quotes
    [4] => anonquotedstring
    [5] => 83448545
    [6] => 1210597346 + '000'
    [7] => 1241722133 + '000')
)

【讨论】:

  • Christ.... 我觉得自己很笨,哈哈... 做 PHP 编码已经八年了,从来没有使用过那个函数。
【解决方案3】:

通过一些回顾,你可以获得接近你想要的东西:

$test = "(some_array, 'some, string goes here','another_string','this string may contain \"double quotes\" but, it can\'t split, on escaped single quotes', anonquotedstring, 83448545, 1210597346 + '000', 1241722133 + '000')";
preg_match_all('`
(?:[^,\']|
   \'((?<=\\\\)\'|[^\'])*\')*
`x', $test, $result);
print_r($result);

给你这个结果:

Array
(
    [0] => Array
        (
            [0] => (some_array
            [1] => 
            [2] =>  'some, string goes here'
            [3] => 
            [4] => 'another_string'
            [5] => 
            [6] => 'this string may contain "double quotes" but, it can\'t split, on escaped single quotes'
            [7] => 
            [8] =>  anonquotedstring
            [9] => 
            [10] =>  83448545
            [11] => 
            [12] =>  1210597346 + '000'
            [13] => 
            [14] =>  1241722133 + '000')
            [15] => 
        )

    [1] => Array
        (
            [0] => 
            [1] => 
            [2] => e
            [3] => 
            [4] => g
            [5] => 
            [6] => s
            [7] => 
            [8] => 
            [9] => 
            [10] => 
            [11] => 
            [12] => 0
            [13] => 
            [14] => 0
            [15] => 
        )

)

【讨论】:

  • 第二个有 "eg s 0" 的数组是什么?你打算把它扔掉吗?
【解决方案4】:

我在这里支持使用 CSV 解析器,这就是它们的用途。

如果你被正则表达式卡住了,你可以使用

preg_match_all(
    '/\s*"    # either match " (optional preceding whitespace),
     (?:\\\\. # followed either by an escaped character
     |        # or
     [^"]     # any character except "
     )*       # any number of times,
    "\s*      # followed by " (and optional whitespace).
    |         # Or: do the same thing for single-quoted strings.
    \s*\'(?:\\\\.|[^\'])*\'\s*
    |         # Or:
    [^,]*     # match anything except commas (i.e. any remaining unquoted strings)
    /x', 
    $subject, $result, PREG_PATTERN_ORDER);
$result = $result[0];

但是,如您所见,这很丑陋且难以维护。为工作使用正确的工具。

【讨论】:

    猜你喜欢
    • 2019-05-29
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-14
    • 2011-05-08
    • 1970-01-01
    相关资源
    最近更新 更多