【问题标题】:Regex - Ignore some parts of string in match正则表达式 - 忽略匹配中字符串的某些部分
【发布时间】:2013-06-06 19:44:10
【问题描述】:

这是我的字符串:

address='St Marks Church',notes='The North East\'s premier...'

我用来通过match_all 抓取各个部分的正则表达式是

'/(address|notes)='(.+?)'/i'

结果是:

地址 => 圣马可教堂
notes => 东北\

如何让它忽略注释的 \' 字符?

【问题讨论】:

  • 您是否只想在表达式中考虑字母数字字符?
  • 在 ' 和第二个 ' 之间基本上没有任何内容,除了 \'。恐怕我是一个正则表达式新手,所以可能第一点错了?

标签: regex preg-match-all


【解决方案1】:

不确定你是用heredoc还是双引号包裹你的字符串,但是一种不那么贪婪的方法:

$str4 = 'address="St Marks Church",notes="The North East\'s premier..."';
preg_match_all('~(address|notes)="([^"]*)"~i',$str4,$matches);
print_r($matches);

输出

Array
(
    [0] => Array
        (
            [0] => address="St Marks Church"
            [1] => notes="The North East's premier..."
        )

    [1] => Array
        (
            [0] => address
            [1] => notes
        )

    [2] => Array
        (
            [0] => St Marks Church
            [1] => The North East's premier...
        )

)

preg_split 的另一种方法:

//split the string at the comma
//assumes no commas in text
$parts = preg_split('!,!', $string);
foreach($parts as $key=>$value){
    //split the values at the = sign
    $parts[$key]=preg_split('!=!',$value);
    foreach($parts[$key] as $k2=>$v2){
        //trim the quotes out and remove the slashes
        $parts[$key][$k2]=stripslashes(trim($v2,"'"));
    }
}

输出如下:

Array
(
    [0] => Array
        (
            [0] => address
            [1] => St Marks Church
        )

    [1] => Array
        (
            [0] => notes
            [1] => The North East's premier...
        )

)

超级慢的老派方法:

$len = strlen($string);
$key = "";
$value = "";
$store = array();
$pos = 0;
$mode = 'key';
while($pos < $len){
  switch($string[$pos]){
    case $string[$pos]==='=':
        $mode = 'value';
        break;
    case $string[$pos]===",":
        $store[$key]=trim($value,"'");
        $key=$value='';
        $mode = 'key';
        break;
    default:
        $$mode .= $string[$pos];
  }

  $pos++;
}
        $store[$key]=trim($value,"'");

【讨论】:

  • 你的第一个方法调整输入字符串以适应方法,这个方法应该被删除。第二个使用preg_split (),其中explode() 是明智的函数调用。此外,如果\' 在字符串中是可能的,那么可以公平地假设,= 也是可能的。第三个,我还没有测试,但它要么有错字,要么正在使用应尽可能避免的可变变量。
  • 我删除了我的反对票,因为我很欣赏你试图修正你的答案。可悲的是,我觉得我不得不重新投票,因为这个答案暗示了糟糕和/或不可靠的方法。
  • 对糟糕的数据存储方法做出让步是绝对不可取的。此文本流应存储在 JSON、XML 甚至 CSV 中,并以理想的行业标准方法进行处理。不过感谢您的意见。
【解决方案2】:

因为您已发布您正在使用match_all 并且您的个人资料中的顶部标签是phpwordpress,所以我认为假设您将preg_match_all() 与php 一起使用是公平的。

以下模式将匹配构建所需关联数组所需的子字符串:

生成全字符串匹配和 1 个捕获组的模式:

  1. /(address|notes)='\K(?:\\\'|[^'])*/(166 步,demo link
  2. /(address|notes)='\K.*?(?=(?&lt;!\\)')/(218 步,demo link

生成 2 个捕获组的模式:

  1. /(address|notes)='((?:\\\'|[^'])*)/(168 步,demo link
  2. /(address|notes)='(.*?(?&lt;!\\))'/(209 步,demo link

代码:(Demo)

$string="address='St Marks Church',notes='The North East\'s premier...'";

if(preg_match_all("/(address|notes)='\K(?:\\\'|[^'])*/",$string,$out)){
    $result=array_combine($out[1],$out[0]);
}
var_dump($result);

echo "\n---\n";

if(preg_match_all("/(address|notes)='((?:\\\'|[^'])*)/",$string,$out,PREG_SET_ORDER)){
    $result=array_combine(array_column($out,1),array_column($out,2));
}
var_dump($result);

输出:

array(2) {
  ["address"]=>
  string(15) "St Marks Church"
  ["notes"]=>
  string(28) "The North East\'s premier..."
}

---
array(2) {
  ["address"]=>
  string(15) "St Marks Church"
  ["notes"]=>
  string(28) "The North East\'s premier..."
}

模式 #1 和 #3 使用替代项来允许非撇号字符或不以反斜杠开头的撇号。

模式 #2 和 #4(使用 php demo 实现时需要额外的反斜杠)使用环视来确保反斜杠前面的撇号不会结束匹配。

一些注意事项:

  • 使用捕获组、备选方案和环视会降低模式效率。限制这些组件的使用将提高性能。使用否定字符类通常可以提高性能。

  • 在尝试减少捕获组时,使用\K(重新启动全字符串匹配)非常有用,它可以减小输出数组的大小。

【讨论】:

  • @PaulPhillips 4 年后,您可能不再是 regex 的新手。请查看此页面上的所有答案。遗憾的是,此页面上的其他答案不准确/不正确,并且随着时间的推移已经收集了赞成票(这意味着他们多年来一直在误导读者)。如果您对我的答案有任何疑问或其他答案不正确的原因,我很乐意为您解释。
  • 嘿,米克,你在抄袭每个人过去的答案还是只是我的?
  • 我在另一个 StackExchange 站点上研究另一个问题时偶然发现了这个页面。我的行为没有恶意。如果我想成为一个巨魔,我会叫你名字,或者更简单地不发表评论。不,我所做的是确定一个包含 3 个错误答案的页面(在 anubhava 删除他之后现在是 2 个),有理由否决错误的错误答案,留下解释性 cmets(带有演示链接),编辑问题,并提供全面而周到的回答。我所做的应该只考虑“内容改进”。
  • 我猜它曾经有效(尽管我不确定如何)否则人们只是看了一眼并认为它有效,尽管它被标记为答案,所以它可能帮助 OP 弄清楚出他们的问题。随便。
  • 它从未按预期工作。 OP盲目地相信答案。随着盲人多年来对盲人的信任,雪球越来越大。
【解决方案3】:

你应该匹配一个没有反斜杠的结束引号,因此:

(address|notes)='(.*?)[^\\]'

这个[^\\] 强制紧接在' 字符之前的字符是反斜杠以外的任何字符。

【讨论】:

  • 如果输入是:"address='.',notes='The North East\'s premier...'" 会起作用吗?
  • 正如@anubhava 所暗示的那样,这个答案是不正确的,并且会破坏预期的返回值。 regex101.com/r/90fBSr/1(被低估为误导)
猜你喜欢
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
  • 2013-01-07
  • 1970-01-01
  • 2013-09-06
相关资源
最近更新 更多