2016-05-29 88 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

'|'在字符類外部是一個交替操作符。類,它是一個字面管道符號 –