2011-05-26 126 views
2

當我讀到this XKCD comic的alt(技術標題)文字時,我開始好奇維基百科中的每篇文章最終都指向哲學文章。於是我開始製作一個Web應用程序,顯示使用PHP「指向」哪些文章。如何刪除「匹配」括號之間的文本?

(PS:不擔心流量 - 因爲我會私下使用它,不會發出太多的請求,維基百科服務器)

要做到這一點,我有括號和斜體字之間移除文本,並獲得第一個鏈接。其他的事情可以用PHP Simple HTML DOM Parser可以實現,但刪除括號內文字是問題..

如果有括號沒有括號,然後我可以使用這個表達式:\([^\)]+\),但是,像the article about German language,有一些文章都重疊括號(例如:German (Deutsch [ˈdɔʏtʃ] (listen)) is..),並且以上RegEx無法處理這些情況,因爲[^\)]*\)發現第一個關閉括號,而不是匹配關閉括號。 (其實上面的情況,因爲有兩個封閉括號之間沒有文字不成爲問題,但是當有兩大右括號之間的聯繫就成了一個大問題。)

一個骯髒的解決方案,我能想到是這樣的:

$s="content of a wikipedia article";$depth=0;$s2=""; 
for($i=0;$i<strlen($s);$i++){ 
    $c=substr($s,$i,1); 
    if($c=='(')$depth++; 
    if($c==')'){if($depth>0)$depth--;continue;} 
    if($depth==0) $s2.=$c; 
} 
$s=$s2; 

然而,因爲它減少了一個字符串轉換成單個字符,並且看起來不必要的,我不喜歡這種解決方案

是否有其他方式在一對(匹配)括號刪除文本?

例如,我要讓這樣的文字:

blah(asdf(foo)bar(lol)asdf)blah 

成這樣:

blahblah 

,但不喜歡這樣的:

blahbarasdf)blah 

編輯:從埃米爾維克斯特羅姆的回答評論,我意識到上述的考慮ach(刪除括號之間的文本)可以刪除包含括號的鏈接。然而,我仍然希望上述問題的答案,因爲我遇到過類似的問題,我想知道答案...

所以我的問題仍然是:如何刪除匹配的括號之間的文本?

+0

我從http://en.wikipedia.org/wiki/Betrayer_of_Worlds隨機開始。經過20多條鏈接,我確實最終成爲了哲學。 – deceze 2011-05-26 08:35:03

+0

Yeop,你進入一個哲學/現實循環;) – Dan 2012-08-19 12:33:24

回答

1

太好了!我看到有人在清理維基百科純文本內容時遇到了問題。這裏是你如何使用它。

cleanBraces("blah(asdf(foo)bar(lol)asdf)blah", "(", ")") 

將返回

blahblah

您可以通過任何類型的括號。像[和]或{和}

這裏是我的源代碼。

function cleanBraces($source, $oB, $eB) { 
    $finalText = ""; 
    if (preg_match("/\\$oB.*\\$eB/", $source) > 0) { 
     while (preg_match("/\\$oB.*\\$eB/", $source) > 0) { 
      $brace = getBracesPos($source, $oB, $eB); 
      $finalText .= substr($source, 0, $brace[0]); 
      $source = substr($source, $brace[1] + 1, strlen($source) - $brace[1]); 
     } 
     $finalText .= $source; 
    } else { 
     $finalText = $source; 
    } 
    return $finalText; 
} 

function getBracesPos($source, $oB, $eB) { 
    if (preg_match("/\\$oB.*\\$eB/", $source) > 0) { 
     $open = 0; 
     $length = strlen($source); 
     for ($i = 0; $i < $length; $i++) { 
      $currentChar = substr($source, $i, 1); 
      if ($currentChar == $oB) { 
       $open++; 
       if ($open == 1) { // First open brace 
        $firstOpenBrace = $i; 
       } 
      } else if ($currentChar == $eB) { 
       $open--; 
       if ($open == 0) { //time to wrap the roots 
        $lastCloseBrace = $i; 
        return array($firstOpenBrace, $lastCloseBrace); 
       } 
      } 
     } //for 
    } //if 
} 
+0

謝謝!...但是好像它不是很有效率.. – JiminP 2011-05-26 09:34:29

3

您可以查看recursive patterns,這應該能夠解決問題。

當我閱讀漫畫時,我沒有意志力讓我的頭繞過遞歸模式,所以我簡化了它找到一個鏈接,然後檢查它是否在括號中。這裏是我的解決方案:

//Fetch links 
    $matches = array(); 
    preg_match_all('!<a [^>]*href="/wiki/([^:"#]+)["#].*>!Umsi', $text, $matches); 
    $links = $matches[1]; 
    //Find first link not within parenthesis 
    $found = false; 
    foreach($links as $l) { 
    if(preg_match('!\([^)]+/wiki/'.preg_quote($l).'.+\)!Umsi', $text)) { 
     continue; 
    }else{ 
     $found = true; 
     break; 
    } 
    } 

這裏是我的整個腳本:http://lajm.eu/emil/dump/filosofi.phps

+0

+1(因爲這是一個很好的方式來找到鏈接),但這個答案不是我想要的,因爲我希望通用的方法來刪除括號之間的文本..對不起:( – JiminP 2011-05-26 08:42:06

+0

是的,我知道它是次優的,因爲它甚至沒有捕捉到你所要求的那些鏈接)。我用我的腳本採取了很多捷徑。如果你檢查我的完整腳本,你會看到我如何去除嵌套的'

...
',這是一個類似的問題。 – 2011-05-26 08:45:51

+0

最糟糕的是,還有包含括號的鏈接,並且你不想刪除這些! – 2011-05-26 08:49:31