2008-11-09 119 views
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>. 
+0

如果你想青睐返回的人帮助你,登录,对于有用的答案投票和接受,解决你的问题之一(如果有一个做的)。 – Tomalak 2008-11-09 17:32:01

回答

4

您可以搜索此常规表情:

(<a[^>]*>.*?</a>)|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>"; 
    } 
} 
0

正则表达式:

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

更换:

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

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

这应该用替换中的链接替换“巴黎”的所有发生。它只是检查在“巴黎”之前是否关闭所有开放的a-Tags。

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内。当您将该图像的标题 - 属性设置为“巴黎”时,该“巴黎”也将被替换。这不是你想要的。尽管如此,我仍然无法用简单的正则表达式完全解决您的问题。

+0

你确定你的'!'符号?您使用哪种正则表达式的方言? – 2008-11-09 16:59:48

+0

@Jonathan:在PHP中,只要在开始和结束时相同,就可以使用任何分隔符。有用避免转义内容... @okoman:我认为你不应该在单引号字符串中使用双引号。也许你可以通过非格雷迪匹配来增强RE。 – PhiLho 2008-11-09 17:02:50

+0

@Jonathan:我认为如果我使用非贪婪的匹配,就不一定明白a-Element必须关闭。 (因为开始标签必须像关闭标签一样频繁出现)。 我使用了正则表达式评估器(http://regexp-evaluator.de)。它产生了引用的字符串,所以它不是我的错;-) Chaning那... – okoman 2008-11-09 17:09:51

3

这种问题的传统答案:使用真正的HTML解析器。因为RE在处理上下文时并不擅长。而HTML是复杂的,一个'a'标签可以有或没有属性,以任何顺序,在链接中可以有HTML或没有HTML等。

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>”,否则第二步将失败(直到您更改第二个正则表达式)。
  • BTW:正则表达式#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>

0

如果您在这种情况下不限于使用正则表达式,那么对于可以在其中定义此r的语言,XSLT是一个不错的选择因为它'理解'XML。

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

-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模块,并且您只需要加载散列,就会感到惊讶。

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; 
    }