如何在第一个特定字符之前停止匹配?

时间:2017-02-11 11:12:29

标签: php regex

这是我的模式(Live example):

(?:"|")id(?:"|"):(?:"|")(.{0,200}?)(?:"|").{0,200}?(?:"|")urn:li:fs_miniCompany:65514(?:"|")

如您所见,它将后续字符串与第一个捕获组匹配:

/p/3/005/07a/356/1399435.png","$type":"com.linkedin.voyager.common.MediaProcessorImage","$id":

但这是预期的结果:

/p/3/005/07a/356/1399435.png

我该怎么做?

注意:我可以使用[^&]+停止匹配,但在这种情况下,会引发Catastrophic Backtracking错误。

2 个答案:

答案 0 :(得分:0)

您可以使用负向前瞻来匹配除一系列字符之外的所有内容。我还建议不要使用{0,200}因为它似乎是随机的。此模式与第一个PNG路径匹配。如果你想拥有最后一个,我会使用更具体的选择器,而不是使用{0,200}

(?:"|")id(?:"|"):(?:"|")(.*?)(?:"|").*?(?!").*?(?:"|")urn:li:fs_miniCompany:65514(?:"|")

答案 1 :(得分:0)

拥有结构化数据时,请勿使用字符串方法。您实际上正在搜索html <code>标记内的JSON字符串中的内容。 使用XPath提取包含子串"urn:li:fs_miniCompany:65514"的{​​{1}}标记文本是一项简单的任务,可以大大减少搜索范围。

然后您需要做的就是进行少量更改以获取JSON字符串(修剪不需要的字符并用双引号替换&quote;实体)

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTMLFile('yourfile.html'); // or $dom->loadHTML($yourstring);

$xp = new DOMXPath($dom);

$codeContent = $xp->evaluate('string(//code[contains(., "urn:li:fs_miniCompany:65514")])');

$json = str_replace('&quote;', '"', trim($codeContent, "\r\n \t\\n"));
$arr = json_decode($json, true);

print_r(array_column($arr['included'], 'id'));

你只需要找到如何根据json结构选择你想要的那个(使用print_r($arr)来可视化它)

关于您的模式的一般注意事项:

  • 避免使用交替启动模式(我没有看到任何写(?:&quote;|")的理由,因为每个引号似乎都被其html实体替换。&quote;应该足够了。) 当没有其他方法时:
    • 尝试使用STUDY修饰符:/pattern/S
    • 尝试使用第一种角色识别技术以这种方式构建您的模式:/(?=[&"])(?:&quote;|").../或者这样:/[&"](?:(?<=&)quote;|(?<=")).../
    • 在最坏的情况下尝试两种模式(启动带有文字字符串的模式提供了很高的改进,因为快速算法在正则表达式引擎启动其正常行走之前找到模式可能成功的所有位置)
  • a.*b.*c (如a.*?b.*?ca.{1,n}b.{1,n}ca.{1,n}?b.{1,n}?c是众所周知的灾难性回溯来源。这种模式允许主题字符串中的单个位置组合太多,并且在失败之前需要很多步骤和时间,因为每个组合都经过测试。
  • 尝试编写尽可能快失败的模式。