3

我想编写一个正则表达式,用链接替换单词 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>.
4

7 回答 7

6

这很难一步完成。编写一个这样的正则表达式几乎是不可能的。

尝试两步法。

  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”一词,没有其他字符。每个“ Paris”都变成“ <a href"...">Paris</a>”,否则第二步将失败(直到您更改第二个正则表达式)。
  • 顺便说一句:regex #2 明确允许这样的结构:

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

    剩余链接来自步骤一,步骤二的替换结果将是:

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

于 2008-11-09T16:54:21.783 回答
4

您可以搜索此正则表达式:

(<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>";
    }
}
于 2008-11-11T09:07:51.567 回答
3

此类问题的传统答案:使用真正的 HTML 解析器。因为 RE 并不擅长在上下文中操作。而且 HTML 很复杂,“a”标签可以有或没有属性,以任何顺序,可以在链接中是否有 HTML,等等。

于 2008-11-09T16:32:10.733 回答
0

正则表达式:

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

替换:

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

$1 指的是第一个子模式(至少在 PHP 中)。根据您使用的语言,它可能会略有不同。

这应该用替换中的链接替换所有出现的“巴黎”。它只是检查所有打开的 a-Tag 在“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-Element 内。当您将该图像的标题属性设置为“巴黎”时,该“巴黎”也将被替换。这不是你想要的。尽管如此,我认为无法使用简单的正则表达式完全解决您的问题。

于 2008-11-09T16:29:21.567 回答
0

如果您不限于在这种情况下使用正则表达式,那么 XSLT 是您可以定义此替换的语言的不错选择,因为它“理解”XML。

您定义了两个模板:一个模板查找链接并删除那些没有“Paris”作为正文的链接。另一个模板查找其他所有内容,将其拆分为单词并添加标签。

于 2008-11-09T23:06:23.450 回答
0
  $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;
  }
于 2010-08-12T12:55:43.907 回答
-2

正则表达式不会替换。语言可以。

语言和库也会从包含您关心的单词列表的数据库或文件中读取,并将 URL 与其名称相关联。这是我可以想象的最简单的替换我的单个正则表达式(perl 用于替换语法。)

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模块可以做到这一点,我会感到惊讶,而您只需要加载哈希。

于 2008-11-10T01:01:26.993 回答