如何在不同格式

时间:2017-02-10 22:50:17

标签: php regex pcre

我需要解析并处理推送到我们的webservice中的输入数据,作为来自第三方的(UTF-8)文本文件。输入文件包含一般形式的标签

<{ _N ('some_domain_id','this can be an arbitary string',{'a':'b','c':'d'}) }>
-- --   --------------   ------------------------------  -----------------  --
        ^                 ^                              ^
        i need to         |                              this part is 
        extract this      and this (payload)             optional

这些标签无论如何都可以出现在文本文件中,不能对它们的分布和标签之间的什么做出任何假设。此外,对于任何给定的有效标记,<{_N}>也会出现,但两者之间可能存在空格而不会中断这些值(例如<{和{{1}之间}) 有了这些信息,我的初始测试集是有限的,我当前的实现是一个正则表达式以及_N

的结果分割
  • 正则表达式,(示例:https://regex101.com/r/NuJD2V/1
  • 然后将结果匹配/<{\s*_N\s*\(([^\)]*)\)\s*}>?/g'some_domain_id' , 'this can be an arbitary string',{'a':'b','c':'d'}
  • 分开
  • 使用str_getcsv($match,',','\'','\\')结果的前两个部分,将其他结果视为可选
  • 之后,str_getcsvsome_domain_id可以根据需要进行裁剪和处理

服务现在已经有一段时间了,我必须意识到尽管绝大多数标签都被正确捕获,但是有少量标签包含异常,并且无法被此实现识别。

警告(有效负载部分可能发生的事情):

  • 有效负载中的括号
  • 有效负载this can be an arbitary string
  • 中的转义引号
  • _N调用的最外面括号后面的可选修饰符(见下文)

以下是我发现的一些无法解析或产生错误结果的样本标签(甚至比不识别更糟糕)。

\'

- 无法识别,请注意括号,它们可以出现在数据字符串的任何位置,它们甚至不需要平衡(例如:https://regex101.com/r/BCiaaj/1

<{_N( 'some_domain_id' , 'this can ( be an arbitary ) string',{'a':'b','c':'d'})}>
  • 无法识别,请注意_N元素最外侧括号后面的额外(可选)修饰符。修饰符可以包含不同的字母(e,r,w)和一个任意字符串参数,链运算符<{_N( 'some_domain_id' , 'this can be an arbitary string' {'a':'b','c':'d'})|e('modifier')}> <{_N( 'some_domain_id' , 'this can be an arbitary string')|e('modifier')}> 周围也可能有空格(例如:https://regex101.com/r/XmR2uO/1

在实验上,我已经尝试了一些其他正则表达式,但它们总是在我的扩展测试集中的一个或多个标记上失败,例如。

  • | - 捕获修饰符大小写,但在相关字符串中的括号上失败

所以我的问题是因为我不是真正的正则表达式专家

  • 这是否可以用正则表达式解决?如果是这样,任何人都可以向我暗示正确的方向吗?
  • 有没有更好的解决方案可以在vanilla php 7+中安装/使用一些外部库

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

您可以使用

<{\s*_N\s*\(\s*'([^\\']*(?:\\.[^\\']*)*)'\s*,\s*'([^\\']*(?:\\.[^\\']*)*)'\s*(.*?)}>

请参阅regex demo

<强>详情:

  • <{\s* - <{加0+空格
  • _N - 标签开始
  • \s*\(\s* - 包含0 +空格的(
  • '([^\\']*(?:\\.[^\\']*)*)' - 单引号字符串文字,可能包含转义的单引号和其他字符(内部内容被捕获到捕获组#1中)
  • \s*,\s* - 包含0 +空格的,
  • '([^\\']*(?:\\.[^\\']*)*)' - 单引号字符串文字,可能包含转义的单引号和其他字符(内部内容被捕获到捕获组#2中)
  • \s* - 0+ whitespaces
  • (.*?) - 在第一个
  • 之前尽可能少的0个字符
  • }> - 文字字符序列}>

答案 1 :(得分:0)

为什么你不能只检索你需要的部分(在单引号中);

//example 1
$str = '<{_N( \'some_domain_id\' , \'this can ( be an arbitary ) string\',{\'a\':\'b\',\'c\':\'d\'})}>';
test_pregex($str);

//example 2
$str = '<{_N(\'some_domain_id\'      , \'this can ( be an arbitary ) string\'  ,{\'a\':\'b\',\'c\':\'d\'})}  >';
test_pregex($str);

//example 3
$str = '<{_N( \'some_domain_id\' , \'this can ( be an arbitary ) string\')|e(\'modifier\')}>';
test_pregex($str, '\'modifier\'');

function test_pregex($str, $optional = "{'a':'b','c':'d'}") {
    $re = '/\'([^\']*?)\'|(\{\'[^\']*?\'.+?})/m';
    preg_match_all($re, $str, $matches);
    $matches = $matches[0];
    var_export($matches);   
    assert($matches[0] == "'some_domain_id'");
    assert($matches[1] == "'this can ( be an arbitary ) string'");
    assert($matches[2] == $optional);
}

输出将是所有三种情况,没有断言警告。然后,您可以进一步处理所需内容。