Как убрать текст между «совпадающими» скобками? - PullRequest
2 голосов
/ 26 мая 2011

Когда я прочитал alt (с технической точки зрения) текст этого комикса XKCD , мне стало любопытно, указывают ли все статьи в Википедии на статью по философии. Поэтому я начал создавать веб-приложение, которое отображает, на какие статьи он «указывает», используя PHP.

(PS: не беспокойтесь о трафике - потому что я буду использовать его в частном порядке и не буду отправлять слишком много запросов на сервер Википедии)

Чтобы сделать это, я должен удалить текст между скобками и курсивом и получить первую ссылку. Другие вещи могут быть достигнуты с помощью PHP Simple HTML DOM Parser , но проблема заключается в удалении текста в скобках ..

Если в скобках нет скобок, то я мог бы использовать этот RegEx: \([^\)]+\), однако, как и статья о немецком языке , есть некоторые статьи с накладными скобками (например: 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

Редактировать: из комментария к ответу Эмиля Викстрёма я понял, что вышеуказанный подход (убрать тексты в скобках) может удалить ссылку, содержащую скобки. Однако мне все еще нужен ответ на вышеуказанную проблему, поскольку я уже сталкивался с подобной проблемой и хочу знать ответ ...

Так что мой вопрос по-прежнему: как убрать текст между соответствующими скобками?

Ответы [ 2 ]

3 голосов
/ 26 мая 2011

Вы можете проверить рекурсивные шаблоны , которые должны быть в состоянии решить эту проблему.

Когда я читал комикс, у меня не было силы воли, чтобы разобраться в рекурсивных шаблонах, поэтому я упростила ее, чтобы найти ссылку, и только потом проверила, есть ли она в скобках.Вот мое решение:

  //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

1 голос
/ 26 мая 2011

Отлично!Я вижу кого-то с проблемой, с которой я столкнулся при очистке текстового содержимого Википедии.Вот как вы его используете.

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

вернет

бла-бла

Вы можете передать любой тип скобок.Как [и] или {и}

Вот мой исходный код.

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...