从字符串中提取多个匹配项的 PHP 正则表达式

8

我正在尝试制作一个PHP正则表达式,从一个字符串中提取多个部分/条件...让我向您展示一下; 这是总文件内容的摘录(实际内容包含数百个这些分组):

part "C28"
{ type       : "1AB010050093",
  %cadtype   : "1AB010050094",
  shapeid    : "2_1206",
  descr      : "4700.0000 pFarad 10.00 % 100.0 - VE5-VS3",
  insclass   : "CP6A,CP6B",
  gentype    : "RECT_032_016_006",
  machine    : "SMT",
  %package   : "080450E",
  %_item_number: "508",
  %_Term_Seq : "" }
part "C29"
{ type       : "1AB008140029",
  shapeid    : "2_1206",
  descr      : "150.0000 pFarad 5.00 % 100.0 Volt NP0 CERAMIC CAPACITOR",
  insclass   : "CP6A,CP6B",
  gentype    : "RECT_032_016_006",
  machine    : "SMT",
  %package   : "080450E",
  %_item_number: "3",
  %_Term_Seq : "" }

如您所见,摘录中的数据重复了两次。我需要搜索整个文件并提取以下内容:
  • 在单词“part”之后的字符串——即“C28”或“C29”
  • 在“type”属性之后的字符串——即“1AB010050093”或“1AB008140029”
因此,基本上,我需要从这个文件中获取所有零件引用和相关类型...但我不确定最好的方法是什么。
如果需要更多信息来帮助,请告知...先感谢您!

你为什么不使用Json解析器来处理这种数据类型呢? - Ro Yo Mi
1
@Denomales 虽然看起来相似,但这个例子不是 JSON 数据,也不能使用 PHP 的 json_decode 函数。 - Matt Browne
好的,我必须问一下。 - Ro Yo Mi
2个回答

12

描述

这个表达式将会:

  • 捕获组名为ref
  • 捕获typedescr字段的值。
  • 当捕获type字段时,应该将其放入名为partnumber的命名组中。
  • 字段可以以任何顺序出现在主体中。
  • descr字段是可选的,只有在存在时才应该被捕获。括号(?:...)?用于使descr字段变为可选项。

请注意,这是一个单一的表达式,所以您需要使用x选项让正则表达式引擎忽略空格。

^part\s"(?P<ref>[^"]*)"[^{]*{
(?:(?=[^}]*\sdescr\s*:\s+"(?P<descr>[^"]*)"))?
(?=[^}]*\stype\s*:\s+"(?P<type>[^"]*)")

在此输入图片描述

PHP示例代码:

输入文本

part "C28"
{ type       : "1AB010050093",
  %cadtype   : "1AB010050094",
  shapeid    : "2_1206",
  descr      : "4700.0000 pFarad 10.00 % 100.0 - VE5-VS3",
  insclass   : "CP6A,CP6B",
  gentype    : "RECT_032_016_006",
  machine    : "SMT",
  %package   : "080450E",
  %_item_number: "508",
  %_Term_Seq : "" }
part "C29"
{ type       : "1AB008140029",
  shapeid    : "2_1206",
  descr      : "150.0000 pFarad 5.00 % 100.0 Volt NP0 CERAMIC CAPACITOR",
  insclass   : "CP6A,CP6B",
  gentype    : "RECT_032_016_006",
  machine    : "SMT",
  %package   : "080450E",
  %_item_number: "3",
  %_Term_Seq : "" }
part "C30"
{ type       : "1AB0081400 30",
  shapeid    : "2_1206 30",
  insclass   : "CP6A,CP6B 30",
  gentype    : "RECT_032_016_006 30",
  machine    : "SMT 30",
  %package   : "080450E 30 ",
  %_item_number: "3 30 ",
  %_Term_Seq : "30" }

代码

<?php
$sourcestring="your source string";
preg_match_all('/^part\s"(?P<ref>[^"]*)"[^{]*{
(?:(?=[^}]*\sdescr\s*:\s+"(?P<descr>[^"]*)"))?
(?=[^}]*\stype\s*:\s+"(?P<partnumber>[^"]*)")/imsx',$sourcestring,$matches);
echo "<pre>".print_r($matches,true);
?>

比赛

$matches Array:
(
[ref] => Array
    (
        [0] => C28
        [1] => C29
        [2] => C30
    )

 [descr] => Array
    (
        [0] => 4700.0000 pFarad 10.00 % 100.0 - VE5-VS3
        [1] => 150.0000 pFarad 5.00 % 100.0 Volt NP0 CERAMIC CAPACITOR
        [2] => 
    )

[partnumber] => Array
    (
        [0] => 1AB010050093
        [1] => 1AB008140029
        [2] => 1AB0081400 30
    )

)

@Denomales,你从哪里获取的正则表达式可视化图片? - tristanbailey
1
@tristanbailey,我正在使用debuggex.com。虽然它不支持向后查找、命名捕获组或原子组,但它仍然很方便理解表达式流程。还有regexper.com。他们也做得很好,但它不是实时的,因为你在输入时。 - Ro Yo Mi
@Denomales,非常好的解决方案。我知道我在我的原始帖子中没有谈论这个问题,但是如何将元素[1]和[2]的匹配结果放在一起呢?例如,最终结果中的一个元素应该看起来像:[0] => Array( ['ref'] => C28, ['partnumber'] => 1AB010050093 ) 请注意,我保留了C28与1AB010050093之间的关系,以此类推... - sadmicrowave
1
我更新了答案,展示了如何将部件号作为命名捕获,并在同一运行中捕获其他字段。希望这正是您所寻找的。 - Ro Yo Mi
1
它不起作用是因为示例代码与您提供的示例略有不同。具体来说,这个正则表达式期望字符串“part”出现在行的开头,而在示例链接中,该字符串出现在一些空格之后。要纠正这个问题,只需在“^”后面插入“\s*”,它也应该对您起作用。http://3v4l.org/8cuFb - Ro Yo Mi
显示剩余4条评论

2
假设每个组都具有相同的结构,则可以使用以下模式:

假设每个组都具有相同的结构,则可以使用此模式:

preg_match_all('~([^"]++)"[^{"]++[^"]++"([^"]++)~', $subject, $matches);
print_r($matches);

编辑:

注意:如果您有更多信息需要提取,您可以轻松将数据转换为json格式,例如:

$data = <<<LOD
part "C28"
{ type       : "1AB010050093",
  %cadtype   : "1AB010050094",
  shapeid    : "2_1206",
  descr      : "4700.0000 pFarad 10.00 % 100.0 - VE5-VS3",
  insclass   : "CP6A,CP6B",
  gentype    : "RECT_032_016_006",
  machine    : "SMT",
  %package   : "080450E",
  %_item_number: "508",
  %_Term_Seq : "" }
part "C29"
{ type       : "1AB008140029",
  shapeid    : "2_1206",
  descr      : "150.0000 pFarad 5.00 % 100.0 Volt NP0 CERAMIC CAPACITOR",
  insclass   : "CP6A,CP6B",
  gentype    : "RECT_032_016_006",
  machine    : "SMT",
  %package   : "080450E",
  %_item_number: "3",
  %_Term_Seq : "" }
LOD;
$trans = array( "}\n"   => '}, ' , 'part'  => ''    ,
                "\"\n{" => ':{"' , ':'     => '":'  ,
                "\",\n" => '","' );

$data = str_replace(array_keys($trans), $trans, $data);
$data = preg_replace('~\s*+"\s*+~', '"', $data);
$json_data =json_decode('{"'.substr($data,1).'}');

foreach ($json_data as $key=>$value) {
    echo '<br/><br/>part: ' . $key . '<br/>type: ' . $value->type;    
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接