2016-05-29 84 views
2

嗯,我知道有几个类似的问题,但无法找到任何与此特定情况。preg匹配标签之间的标签之间的相同标签

我拿了一个代码,并根据我的需要调整它,但现在我创建了一个我无法修正的错误。

代码:

$tag = 'namespace'; 
$match = Tags::get($f, $tag); 
var_dump($match); 

    static function get($xml, $tag) { // http://stackoverflow.com/questions/3404433/get-content-within-a-html-tag-using-7-processing 
// bug case  string(56) "<namespaces> 
//  <namespace key="-2">Media</namespace>" 
     $tag_ini = "<{$tag}[^\>]*?>"; $tag_end = "<\\/{$tag}>"; 
     $tag_regex = '/' . $tag_ini . '(.*?)' . $tag_end . '/si'; 

     preg_match_all($tag_regex, 
     $xml, 
     $matches, 
     PREG_OFFSET_CAPTURE); 
     return $matches; 
    } 

正如你所看到的,但如果该标签被嵌套了一个错误:

<namespaces> <namespace key="-2">Media</namespace>

当它应该返回 '媒体',或即使在外面'<namespaces>',然后在里面。

我试着添加“<{$tag}[^\>|^\r\n ]*?>”,^\s+,将*改成* *,以及其他一些在最好的情况下转而只识别错误情况的东西。

也试过"<{$tag}[^{$tag}]*?>"这给了空白,我想它会自行消失。

我是一个正则表达式的新手,我可以告诉解决这个问题只是需要添加不要让一个新的标签打开同一个类型。 或者我甚至可以对我的使用案例使用黑客答案,即排除内部文本是否有新的线条托架。

任何人都可以得到正确的语法吗?


您可以查看这里的文字摘录:http://pastebin.com/f2naN2S3


提议的变更后:$tag_ini = "<{$tag}\\b[^>]*>"; $tag_end = "<\\/{$tag}>";它的工作的例子的情况下,但不是这一个:

<namespace key="0" /> 
     <namespace key="1">Talk</namespace> 

因为它导致:

<namespace key="1">Talk" 

这是因为数字和“和字母被认为是在字边界内。我怎么解决这个问题?

+0

目前正在努力:$ tag_regex = '/'。 $ tag_ini。 “[^ {$ tag_ini}] *?” 。 $ tag_end。 '/ SI'; – Cristo

+0

如果您对此表示歉意,您可以评论它不是一个好问题的原因 – Cristo

+1

但是,如果您尝试使用正则表达式处理XML,那么对于一个很好的描述和一个片段,可能会出现更多的关于此问题的提示。至于你为什么得到命名空间标签,你没有使用单词边界:'$ tag_ini =“<{$tag}\\b[^>] *>”;'。然而,这不会解决嵌套标签的问题,你需要一个[递归正则表达式](http://www.regular-expressions.info/recurse.html)。不过,你最好使用DOM解析来解析标签之间的内容。 –

回答

1

主要问题是您在开始标记后没有使用单词边界,因此模式中的namespace也可能匹配namespaces标签和许多其他。

随后的问题是,<${tag}\b[^>]*>(.*?)<\/${tag}>模式将火上,如果有一个自闭namespace标签遵循的“正常”配对开/关namespace标签。因此,您需要在>(请参阅demo)之前使用否定顺序(?<!\/),或在\b(请参阅demo)之后使用(?![^>]*\/>)负面预测。

所以,你可以使用

$tag_ini = "<{$tag}\\b[^>]*(?<!\\/)>"; $tag_end = "<\\/{$tag}>"; 
+0

对不起,但我很难理解。正则表达式对我来说似乎是中文:( 你的意思是,如果有,下一个将包含在前一个中,就像在bug例子中一样? 但这与其他人一样:https://regex101.com/r/iC2aN5/1? 我我错过了什么?你可以在演示中设置我的失败,你的作品,所以我可以看到差异? 感谢您的耐心配合 – Cristo

+0

您的正则表达式不允许在任何标签内容中使用''''''。它不匹配任何不是'/>'的文本。为了匹配任何不是'/>'的文本,你需要一个像'(?:(?!\ />)这样的锻炼贪婪标记。)*'。或者展开一个:'[^ \ /] *(?:\ /(?!>)[^ \ /] *)*' –

+0

对于我来说,正则表达式复杂度太高。如果你同意,让我们解决这个用例的问题,一旦完成,我会试着理解为什么。如果不是的话,我感到如此不知所措。 如果我把我的简化为\\ b [^> \ /] *>,那会不会奏效?这似乎确实在我的测试中起作用。因此,把所有东西都放到不是>或/的地方。对 ? – Cristo

1

这可能不是这个想法的答案,但我是用正则表达式生成器搞乱:

<?php 
# URL that generated this code: 
# http://txt2re.com/index-php.php3?s=%3Cnamespace%3E%3Cnamespace%20key=%22-2%22%3EMedia%3C/namespace%3E&12&11 

$txt='arstarstarstarstarstarst<namespace key="-2">Media</namespace>arstarstarstarstarst'; 

$re1='.*?'; # Non-greedy match on filler 
$re2='(?:[a-z][a-z]+)'; # Uninteresting: word 
$re3='.*?'; # Non-greedy match on filler 
$re4='(?:[a-z][a-z]+)'; # Uninteresting: word 
$re5='.*?'; # Non-greedy match on filler 
$re6='(?:[a-z][a-z]+)'; # Uninteresting: word 
$re7='.*?'; # Non-greedy match on filler 
$re8='((?:[a-z][a-z]+))'; # Word 1 

if ($c=preg_match_all ("/".$re1.$re2.$re3.$re4.$re5.$re6.$re7.$re8."/is", $txt, $matches)) 
{ 
    $word1=$matches[1][0]; 
    print "($word1) \n"; 
} 

#----- 
# Paste the code into a new php file. Then in Unix: 
# $ php x.php 
#----- 
?> 
+0

现在,这是一个非常有用的链接。但我正在处理输出,所以我需要别的东西。 我认为这不适用于一个较大的文本,我在这里删减了一个短语,这种情况是解析一个文档。 – Cristo

+0

如果您发布了更多文档,这将有所帮助。 – Alison

+0

我的意思是,任何带有嵌套标签的文本都适用于测试 – Cristo

0

此行正是我需要的

$tag_ini = "<{$tag}\\b[^>|^\\/>]*>"; $tag_end = "<\\/{$tag}>"; 

非常感谢你,你@Alison和@ Wictor为您提供帮助和指导

+0

字符类将符号视为单独的单元,因此,您的'[^> |^\\ />]'是不正确的匹配除'''','|',''''''以外的任何字符 –

+0

我认为|就像'or'运算符:x – Cristo

+1

'|'在字符类外部是一个交替操作符。类,它是一个字面管道符号 –