Регулярное выражение заменяет слово ссылкой - PullRequest
3 голосов
/ 09 ноября 2008

Я хочу написать регулярное выражение, которое заменит слово Paris ссылкой, поскольку только слово не готово к части ссылки.

Пример:

    i'm living <a href="Paris" atl="Paris link">in Paris</a>, near Paris <a href="gare">Gare du Nord</a>,  i love Paris.

станет

    i'm living.........near <a href="">Paris</a>..........i love <a href="">Paris</a>.

Ответы [ 7 ]

6 голосов
/ 09 ноября 2008

Это трудно сделать за один шаг. Написание одного регулярного выражения, которое делает это, практически невозможно.

Попробуйте двухэтапный подход.

  1. Поместите ссылку вокруг каждого существующего "Парижа", независимо от того, существует ли уже другая ссылка.
  2. Найдите все неправильно вложенные ссылки (<a href="..."><a href="...">Paris</a></a>) и удалите внутреннюю ссылку.

Регулярное выражение для первого шага очень просто:

\bParis\b

Регулярное выражение для второго шага немного сложнее:

(<a[^>]+>.*?(?!:</a>))<a[^>]+>(Paris)</a>

Используйте это значение на всей строке и замените его содержимым групп совпадений 1 и 2, эффективно удалив лишнюю внутреннюю ссылку.

Объяснение регулярного выражения # 2 в простых словах:

  • Найти каждую ссылку (<a[^>]+>), за которой, возможно, следует все, что не является само по себе, после чего следует закрывающая ссылка (.*?(?!:</a>)). Сохраните его в группе совпадений 1.
  • Теперь найдите следующую ссылку (<a[^>]+>). Убедитесь, что он есть, но не сохраняйте его.
  • Теперь поищите слово Париж. Сохраните его в группе совпадений 2.
  • Ищите закрывающую ссылку (</a>). Убедитесь, что он есть, но не сохраняйте его.
  • Замените все на содержимое групп 1 и 2, потеряв при этом все, что вы не сохранили.

Подход предполагает следующие побочные условия:

  • Ваш входной HTML не ужасно сломан.
  • Ваш вариант регулярного выражения поддерживает не жадные квантификаторы (. *?) И отрицательные прогнозные утверждения нулевой ширины ((?!:...)).
  • Вы заключаете слово «Париж» только в ссылку на шаге 1, без дополнительных символов. Каждое "Paris" становится "<a href"...">Paris</a>", или второй шаг завершится неудачей (пока вы не измените второе регулярное выражение).
  • Кстати: регулярное выражение # 2 явно допускает такие конструкции:

    <a href="">in the <b>capital of France</b>, <a href="">Paris</a></a>

    Избыточная ссылка приходит с первого шага, результат замены шага 2 будет:

    <a href="">in the <b>capital of France</b>, Paris</a>

4 голосов
/ 11 ноября 2008

Вы можете найти это регулярное выражение:

(<a[^>]*>.*?</a>)|Paris

Это регулярное выражение соответствует ссылке, которую оно фиксирует в первой (и единственной) группе захвата, или слову Paris.

Замените совпадение своей ссылкой, только если группа захвата ничего не соответствует.

например. в C #:

resultString = 
    Regex.Replace(
        subjectString, 
        "(<a[^>]*>.*?</a>)|Paris", 
        new MatchEvaluator(ComputeReplacement));

public String ComputeReplacement(Match m) {
    if (m.groups(1).Success) {
        return m.groups(1).Value;
    } else {
        return "<a href=\"link to paris\">Paris</a>";
    }
}
3 голосов
/ 09 ноября 2008

Традиционный ответ на такой вопрос: используйте настоящий HTML-парсер. Потому что RE не очень хорошо работают в контексте. А HTML сложен, тег 'a' может иметь атрибуты или нет, в любом порядке, может иметь HTML в ссылке или нет, и т. Д.

0 голосов
/ 12 августа 2010
  $pattern = 'Paris';
  $text = 'i\'m living <a href="Paris" atl="Paris link">in Paris</a>,  near Paris <a href="gare">Gare du Nord</a>,  i love Paris.';

  // 1. Define 2 arrays:
  //  $matches[1] - array of links with our keyword
  //  $matches[2] - array of keyword
  preg_match_all('@(<a[^>]*?>[^<]*?'.$pattern.'[^<]*?</a>)|(?<!\pL)('.$pattern.')(?!\pL)@', $text, $matches);

  // Exists keywords for replace? Define first keyword without tag <a>
  $number = array_search($pattern, $matches[2]);

  // Keyword exists, let's go rock
  if ($number !== FALSE) {

    // Replace all link with temporary value
    foreach ($matches[1] as $k => $tag) {
      $text = preg_replace('@(<a[^>]*?>[^<]*?'.$pattern.'[^<]*?</a>)@', 'KEYWORD_IS_ALREADY_LINK_'.$k, $text, 1);
    }

    // Replace our keywords with link
    $text = preg_replace('/(?<!\pL)('.$pattern.')(?!\pL)/', '<a href="">'.$pattern.'</a>', $text);

    // Return link
    foreach ($matches[1] as $k => $tag) {

      $text = str_replace('KEYWORD_IS_ALREADY_LINK_'.$k, $tag, $text);
    }

    // It's work!
    echo $text;
  }
0 голосов
/ 10 ноября 2008

Регулярные выражения не заменяют. Языки делают.

Языки и библиотеки также будут читать из базы данных или файла, в котором содержится список слов, которые вам интересны, и связывать URL с их именем. Вот простейшая замена, которую я могу себе представить, используя мое регулярное выражение (perl используется для синтаксиса replace ).

s/([a-z-']+)/<a href="http:\/\/en.wikipedia.org\/wiki\/$1">$1<\/a>/i

Собственные имена могут работать лучше:

s/([A-Z][a-z-']+)/<a href="http:\/\/en.wikipedia.org\/wiki\/$1">$1<\/a>/gi;

Конечно, "Батон-Руж" станет двумя ссылками для:

<a href="http://en.wikipedia.org/wiki/Baton">Baton</a> 
<a href="http://en.wikipedia.org/wiki/Rouge">Rouge</a>

В Perl вы можете сделать это:

my $barred_list_of_cities 
    = join( '|'
    , sort { ( length $a <=> $b ) || ( $a cmp $b ) } keys %url_for_city_of
    );
s/($barred_list_of_cities)/<a href="$url_for_city_of{$1}">$1<\/a>/g;

Но, опять же, это язык , который реализует набор операций для регулярных выражений, регулярные выражения ничего не делают. (На самом деле, это настолько распространенное приложение, что я был бы удивлен, если бы где-нибудь не было модуля CPAN , который бы делал это, и вам просто нужно загрузить хеш.

0 голосов
/ 10 ноября 2008

Если в этом случае вы не ограничивались использованием регулярных выражений, XSLT является хорошим выбором для языка, на котором вы можете определить эту замену, потому что он «понимает» XML.

Вы определяете два шаблона: Один шаблон находит ссылки и удаляет те ссылки, которые не имеют «Paris» в качестве основного текста. Другой шаблон находит все остальное, разбивает его на слова и добавляет теги.

0 голосов
/ 09 ноября 2008

Регулярное выражение:

!(<a.*</a>.*)*Paris!isU

Замена:

$1<a href="Paris">Paris</a>

$ 1 относится к первому подэлементу (по крайней мере, в PHP). В зависимости от языка, который вы используете, он может немного отличаться.

Это должно заменить все случаи "Париж" со ссылкой в ​​замене. Он просто проверяет, все ли открывающие a-теги были закрыты до «Paris».

Пример PHP:

<?php
$s = 'i\'m living <a href="Paris" atl="Paris link">in Paris</a>, near Paris <a href="gare">Gare du Nord</a>, i love Paris.'; 
$regex = '!(<a.*</a>.*)*Paris!isU'; 
$replace = '$1<a href="Paris">Paris</a>'; 
$result = preg_replace( $regex, $replace, $s); 
?>

Дополнительно:

Это не лучшее решение. Одна ситуация, когда это регулярное выражение не сработает, это когда у вас есть img-Tag, который не находится внутри a-элемента. Когда вы устанавливаете title-Attribute этого изображения в «Paris», этот «Paris» также будет заменен. И это не то, что вы хотите. Тем не менее я не вижу способа полностью решить вашу проблему с помощью простого регулярного выражения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...