字符串解析帮助

4

我有一个类似下面的字符串:

$string = "
<paragraph>apples are red...</paragraph>
<paragraph>john is a boy..</paragraph>
<paragraph>this is dummy text......</paragraph>
";

我想将这个字符串拆分成一个数组,包含在<paragraph></paragraph>标记之间找到的文本。例如像这样:

$string = "
<paragraph>apples are red...</paragraph>
<paragraph>john is a boy..</paragraph>
<paragraph>this is dummy text......</paragraph>
";

$paragraphs = splitParagraphs($string);
/* $paragraphs now contains:
   $paragraphs[0] = apples are red...
   $paragraphs[1] = john is a boy...
   $paragraphs[1] = this is dummy text...
*/

有什么想法吗?

另外,它应该是不区分大小写的,<paragraph>, <PARAGRAPH>, <Paragraph> 应该被视为相同。

编辑: 这不是XML,这里有很多东西会破坏XML的结构,因此我不能使用SimpleXML等工具。我需要一个正则表达式来解析它。

7个回答

5

如果这确实是XML,那么我同意其他答案。但如果它不是有效的XML,只是看起来有点像XML,那么你不应该尝试使用XML解析器进行解析。相反,你可以使用正则表达式:

$matches = array();
preg_match_all(":<paragraph>(.*?)</paragraph>:is", $string, $matches);
$result = $matches[1];
print_r($result);

输出:

Array
(
    [0] => apples are red...
    [1] => john is a boy..
    [2] => this is dummy text......
)

请注意,i 表示不区分大小写,s 允许文本中匹配换行符。所有未包含在段落标签内的文本将被忽略。

谢谢,这个方法可行,但是在数组结果中仍然保留了<paragraph></paragraph>标签,能否通过正则表达式去掉它们? - Ali
嗨,我在这个正则表达式上遇到了问题,如果你能帮忙就太好了。https://dev59.com/jU7Sa4cB1Zd3GeqP6MLK - Ali

2
如果这是一个简单的结构,没有嵌套:
preg_split("#</?paragraph>#i", $string);

忽略空令牌:
preg_split("#</?paragraph>#i", $string, -1, PREG_SPLIT_NO_EMPTY);

来源: http://php.net/manual/zh/function.preg-split.php

preg_split() 函数使用一个正则表达式分隔字符串。

语法:

array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )

参数说明:

  • $pattern:规定搜索模式的字符串(正则表达式)
  • $subject:要分隔的字符串
  • $limit:可选。规定所返回的最大键名数目。
  • $flags:可选。规定特殊标记 (flags):
    • PREG_SPLIT_NO_EMPTY - 如果分割后出现了空字符串,不会把它作为返回数组的元素返回。
    • PREG_SPLIT_DELIM_CAPTURE - 如果设置了此标记,正则表达式中指定的每个分隔符都会被捕获并返回。
    • PREG_SPLIT_OFFSET_CAPTURE - 如果设置了此标记,返回数组的每个元素将是一个数组,其中第一个元素是匹配到的子字符串,第二个元素是这个子字符串在 subject 中的偏移量。

我应该补充一下,这里没有方便的 PHP。正则表达式是正确的,但你可能需要微调一下语法。 - Kobi
应该是,它具有“i”标志。这里我使用#作为正则表达式边界,因为/是正则表达式的一部分。这是常见的避免转义。 - Kobi
当我运行这个程序时,我得到了以下结果: `数组 ( [0] => [1] => 苹果是红色的... [2] => [3] => 约翰是一个男孩.. [4] => [5] => 这是虚拟文本...... [6] => )`所以它能够工作,但同时也产生了很多空元素。您有什么想法可以解决这个问题吗? - Ali

0

这看起来非常像XML。如果确实是,您应该使用PHP的SimpleXMLElement或任何其他XML解析工具。

$xml = new SimpleXMLElement('<root>' . $paragraphs . '</root>');

foreach($xml->paragraph as $paragraph)
{
    // do stuff to $paragraph; it's strval is the contents of the paragraph
}

0

嗯,你应该使用XML解析器,比如SimpleXMLXMLReader

不过,如果你想要快速实现一些东西,以下代码也可以工作:

$string = str_replace("<paragraph>", "", $string);
$string = str_replace("</paragraph>", "", $string);
$paragraphs = explode("\n", $string);

只要每行有一个项目,这个方法就可以工作。如果你把所有内容都放在一行上,那么请使用以下代码替换上面的第二行代码:
$string = str_replace("</paragraph>", "\n", $string);

祝你好运!


0

假设您在段落中有一些将破坏XML格式的内容,或者您只是想更多地了解正则表达式解析,那么这应该可以完成您发布的示例。它并不特别强大,但这就是为什么人们喜欢使用XML的原因,因为它具有形式化语法,使得解析变得容易。或者说更容易。特别是此解决方案取决于正在解析的字符串以段落标记开头并以段落关闭标记结尾,而且每对段落之间没有除空格之外的任何内容。因此,这是您示例问题的非常字面的解决方案。但既然这是您自定义数据格式的唯一现有规范文档,那么这就是我能做到的最好的:)

$string = " <paragraph>apples are red...</paragraph> <paragraph>john is a boy..</paragraph> <paragraph>this is dummy text......</paragraph> ";
$paragraphs = preg_replace('/(^\s*<paragraph>|<\/paragraph>\s*$)/', '', preg_split('/(?<=<\/paragraph>)\s*(?=<paragraph>)/', $string));

这里发生的情况是,在 preg_split 函数调用中,您使用了零宽度回顾断言来查找每个段落的开头和结尾,然后调用 preg_replace 来裁剪掉每个块开头和结尾的标签。最终,您将得到 $paragraphs 的内容。
array (
  0 => 'apples are red...',
  1 => 'john is a boy..',
  2 => 'this is dummy text......',
)

哦,是的..对于不区分大小写,您只需将i添加为两个正则表达式的修饰符。也就是在最后一个斜杠后面添加它。 - intuited

0

在您进行编辑后(不区分大小写,并且标签过大以至于无法被XML解析器处理),以下代码应该可以正常工作:

$paragraphs = array();
$exploded = explode("</", $string);
unset($exploded[count($exploded) - 1]); //remove the useless, final "paragraph>" item
$exploded[0] = str_replace("<paragraph>", "", $exploded[0]); // first item is a special case
foreach($exploded as $item)
{
    array_push($paragraphs, str_replace("paragraph>\n<paragraph>", "", $item));
}

0

如果你真的要解析XML, 那么PHP DOM会很有用。虽然你可能只是举了一个简单的例子,但如果你要解析XML,我建议使用专门的XML API。


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