当我阅读this XKCD comic的alt(技术标题) - 文本时,我开始好奇维基百科中的每篇文章是否最终都指向哲学文章。所以我开始创建一个Web应用程序,显示它使用PHP“指向”的文章。
(PS:不要担心流量 - 因为我会私下使用它,不会向维基百科服务器发送太多请求)
为此,我必须删除括号和斜体之间的文本,并获取第一个链接。使用PHP Simple HTML DOM Parser可以实现其他目的,但删除括号中的文本是问题..
如果括号中没有括号,那么我可以使用此RegEx:\([^\)]+\)
,但是,如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
编辑:从EmilVikström的回答评论中,我意识到上述方法(删除括号中的文本)可能会删除包含括号的链接。但是,我仍然想要上述问题的答案,因为我之前遇到过类似的问题,我想知道答案......
所以我的问题仍然是:如何在匹配的括号中删除文本?
答案 0 :(得分: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;
}
}
答案 1 :(得分: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
}