2011-05-26 102 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