尝试在 php 中使用正则表达式查找标签并获取属性

Trying to find tag and get attributes using regex in php

我在 php 中创建了一个正则表达式来查找 html 行中的标签和属性。 它有效但仅适用于第一个属性而不是重复。 以下代码为我提供了第一个属性和值。

'@<barcode(\s([a-z]+)="([^"]+)").*/>@m'

然后我加了加号让它重复,但它不起作用。

'@<barcode(\s([a-z]+)="([^"]+)")+.*/>@m'

添加加号后会发生什么,它只选择最后一个属性和值。

我只需要一个数组中的所有属性和值,所以我想知道我做错了什么。 这是我正在搜索的可能 html。有时并不总是需要属性,所以我必须考虑到这一点。

<barcode type="C128B" height="10" fontsize="0.4" code="testcode" align="L"/>
<barcode type="Hello"/>
<barcode type="Hello" code="balls"/>
<barcode type="C128B" height="10" fontsize="0.7" code="test" align="L"/>

我有一个关于regex101的例子来查看问题 https://regex101.com/r/jMdA6S/1

我们当前的应用程序可以工作,但只能通过重复以下几行

'@<barcode ([a-z]+)="(.*)" ([a-z]+)="(.*)" ([a-z]+)="(.*)" ([a-z]+)="(.*)" ([a-z]+)="(.*)".*/>@m'

这意味着我每次添加新属性时都必须在正则表达式中添加另一个代码块。 我试图避免这种情况,因为我们有时必须添加一个新属性来添加不同的功能。

您需要将 /g 放在正则表达式的末尾,如下所示:

<barcode(\s([a-z]+)="([^"]+)").*/g>

一个好的做法是使用相关 manipulation tool 解析 HTML 内容。对于您的问题,您可以在读取文件时进行解析(SAX 方法),或者一次加载文件然后访问其内容(DOM 方法)。

这里是 a 执行您需要的方法。如果我不需要保留全部内容,我喜欢使用SAX方式(广泛基于PHP官网的XML Element Structure Example):

<?php
$file = "data.html"; // your file
$depth = array();

function startElement($parser, $tagname, $attrs)
{
    // For each tag encountered
    //   - $tagname contains the name
    //   - $attrs is an associative array name -> value of the attributes

    // Add the code below the code to deal with it:
    echo "<pre>\n";
    echo "Tags : $tagname\n";
    echo "Attributes:\n";
    print_r($attrs);
    echo "</pre>\n";
}

// Create the parser
$xml_parser = xml_parser_create();

// Set element handles for the parser (we just need start element handler, 
// so the end element is set as FALSE
xml_set_element_handler($xml_parser, "startElement", FALSE);

// Open your file
if (!($fp = fopen($file, "r"))) {
    die("Oops.");
}

// Loop reading and parsing the file
while ($data = fread($fp, 4096)) {
    if (!xml_parse($xml_parser, $data, feof($fp))) {
        die("Oops.");
    }
}

// Done. Free your parser.
xml_parser_free($xml_parser);
?>

如果您想匹配无限数量的 xml 对象并从中访问键值对(使用正则表达式),您可能需要为此编写解析器。

我已经为你准备好了工作示例。

   $offset = 0;

   $lines = '
       <barcode type="C128B" height="10" fontsize="0.4" code="testcode" align="L"/>
       <barcode type="Hello"/>
       <barcode type="Hello" code="balls"/>
       <barcode type="C128B" height="10" fontsize="0.7" code="test" align="L"/>
   ';

   while (preg_match('/<(\S*)[\s]*(.*)[\s]*\/>/', $lines, $line_matches, PREG_OFFSET_CAPTURE, $offset))
   {
       // Set offset to the next line
       $offset = $line_matches[0][1] + strlen($line_matches[0][0]);

       // Get the line name
       $name = $line_matches[1][0];

       // Get the line content
       $line_content = $line_matches[2][0];

       if(preg_match_all('/([a-z]+)="([^"]+)"/', $line_content, $key_values_matches))
       {
           // Access all matched keys
           $keys = $key_values_matches[1];

           // Access all matches values
           $values = $key_values_matches[2];

           foreach ($keys as $index => $key) {
               // Access matched value for key
               $value = $values[$index];

               // Do something with your match
               echo "Found match in \"{$name}\" for key \"{$key}\" with value \"{$value}\"\n";
           }
       }

   };

虽然有一些很好的答案,但没有人能够告诉我是否有办法在一个正则表达式中做到这一点,这就是我的问题。但是我不得不屈服并在两个正则表达式中做到这一点's.I 试图避免 2 个正则表达式,因为我认为加号应该重复中间部分。

第一个正则表达式找到标签,我有一个获取属性的 getAttributes 函数。然后 getAttributes 函数将每个属性放入一个平面数组中供我处理。我给出了一个答案,但即使是这个答案也没有真正回答我关于如何在一个正则表达式中执行此操作的问题。但是,我会 post 我所做的工作,以防它对其他人有帮助。

Amessihel 和 Maciej Król 都给出了很好的建议,如果这是一个正在构建的新项目,我可能会采纳这些建议。但是我已经使用了以下代码。

<?php
$str = '<barcode type="C128B" height="10" fontsize="0.4" code="pdfbarcode_content" align="L"/>
<barcode href="Hello"/>
<barcode href="Hello" type="balls"/>
<barcode type="C128B" height="10" fontsize="0.4"/>
<barcode type="C128B" height="10" fontsize="0.4" code="test" align="L"/>';

function getAttributes($attr){  
    preg_match_all('@(?:([a-z]+)="([^"]+)")+@m', $attr, $matches,PREG_SET_ORDER);
    $rArray=[];
    foreach($matches as $line):
        array_push($rArray,$line[1]);
        array_push($rArray,$line[2]);
    endforeach;
    return $rArray;
}
function barcode($file){
    return preg_replace_callback(
        '@<barcode(.*)/>@m',
        function($matches) {
            echo '<pre>'.print_r($matches[1],1).'</pre>';
            echo '<pre>'.print_r(getAttributes($matches[1]),1).'</pre>';
            echo "-----------------------";
            //Here is where I process the array
            return '';
    },
    $file);
}
barcode($str);