【问题标题】:How to do conditional ("if exist" logic) search & replace in Perl?如何在 Perl 中进行条件(“如果存在”逻辑)搜索和替换?
【发布时间】:2016-05-28 21:01:16
【问题描述】:

在我的 Perl 脚本中,我想使用正则表达式进行条件搜索和替换:查找某个模式,如果该模式存在于哈希中,则将其替换为其他内容。

例如,我要搜索“pattern1”和“pattern2”的组合,如果后者存在于哈希中,则将组合替换为“pattern1”和“replacement”。我尝试了以下方法,但它根本没有做任何事情。

$_ =~ s/(pattern1)(pattern2)/$1replacement/gs if exists $my_hash{$2};

我也尝试过类似的东西:

$_ =~ s/(pattern1)(pattern2) && exists $my_hash{$2}/$1replacement/gs;

也什么都不做,好像没有找到匹配一样。

谁能帮我解决这个正则表达式问题?谢谢~

【问题讨论】:

  • 怎么不工作,错误?什么都不做?
  • 等一下...所以 patt2 应该存在于某个哈希值中,好的;但是 patt1 和 patt2 的组合应该存在......在某个字符串中?这是正确的吗?
  • @123 没有错误;它什么也不做。
  • @zdim 好吧,pattern2 确实存在于哈希中。 pattern1 与哈希没有任何关系;我使用这样的“组合”只是为了说明pattern2应该在特定的上下文中匹配。
  • OK ...然后寻找patt1-patt2组合,如果存在则替换为patt1-else?那是你要的吗?我发布了一个快速答案,请查看并告诉我。

标签: regex perl search replace conditional


【解决方案1】:

我会以不同的方式来做。看起来你有一个“搜索这个,替换那个”哈希。

所以:

#!/usr/bin/env perl
use strict;
use warnings;

#our 'mappings'. 
#note - there can be gotchas here with substrings
#so make sure you anchor patterns or sort, so 
#you get the right 'substring' match occuring. 

my %replace = (
    "this phrase" => "that thing",
    "cabbage"     => "carrot"
);

#stick the keys together into an alternation regex. 
#quotemeta means regex special characters will be escaped. 
#you can remove that, if you want to use regex in your replace keys.     
my $search = join( "|", map {quotemeta} keys %replace );
#compile it - note \b is a zero width 'word break' 
#so it will only match whole words, not substrings. 
$search = qr/\b($search)\b/;

#iterate the special DATA filehandle - for illustration and a runnable example. 
#you probably want <> instead for 'real world' use. 
while (<DATA>) {
    #apply regex match and replace
    s/(XX) ($search)/$1 $replace{$2}/g;
    #print current line. 
    print;
}

##inlined data filehandle for testing. 
__DATA__
XX this phrase cabbage
XX cabbage carrot cabbage this phrase XX this phrase
XX no words here
and this shouldn't cabbage match this phrase at all

通过这样做,我们将您的哈希键转换为正则表达式(您可以打印它 - 它看起来像:(?^:\b(cabbage|this\ phrase)\b)

插入到替换模式中。这将在密钥存在时匹配,因此您可以安全地进行替换操作。

注意 - 我添加了quotemeta,因为它会转义键中的任何特殊字符。 \b 是一个“单词边界”匹配,因此它不会在单词中使用子字符串。 (很明显,如果你确实想要那个,那就摆脱它们)

上面给出的输出:

XX that thing cabbage
XX carrot carrot cabbage this phrase XX that thing
XX no words here
and this shouldn't cabbage match this phrase at all

如果你想省略 模式匹配的行,你可以在正则表达式后面加上&amp;&amp; print;

【讨论】:

  • 我仍然无法完全理解它,但它很漂亮:)
  • 这相当简单——您使用交替创建一个(可能非常长的)正则表达式匹配表达式。该替换“捕获”$2,然后您可以在替换的右侧使用它。但是,围绕可能的子字符串有一些陷阱,这意味着您有时必须按长度对键进行排序。
  • 是的,你的代码很好!!说实话,我确实花了一些时间试图弄清楚“map”、“qr”和“compile”东西的用法,但失败了。现在我只是“按原样”使用您的代码,而不知道它的实际含义,它确实在我的代码中有效!谢谢~
【解决方案2】:

有什么问题(如不工作)

if (exists($h{$patt1)) { $text =~ s/$patt1$patt2/$patt1$1replacement/g; }

如果$patt1 存在作为哈希中的键,那么您继续将$patt1$patt2 替换为$patt1$replacement。当然,如果在$text 中找到了$patt1$patt2,否则什么也不会发生。您的第一个代码 sn-p 是循环的,而第二个代码根本不能那样工作。

如果你首先想要$patt1$patt2哈希键,那么你似乎必须慢慢来

if ($str =~ /$patt11$patt2/ && exists $h{$patt2}) {
     $str =~ s/$patt1$patt2/$patt1$replacement/gs;
}

如果这是你想要的,那么它真的很简单:你需要两个不相关的条件,无论你以哪种方式扭转它。不能将它们组合起来,因为它是圆形的。

从结果的角度来看,这些是相同的。如果任一条件失败,则无论您检查它们的顺序如何,都不会发生任何事情。

注意 或者你也不必慢慢来,见Sobrique的帖子。

【讨论】:

  • 感谢您的回复,但这不是我想要的。我真正想要的是:首先,搜索 $patt1$patt2;那么,如果找到匹配并且如果 $patt2 存在于哈希中,则将其替换为 $patt1$replacement。
  • 新添加的代码也不起作用。至于原因,嗯,我的意图来自我正在尝试做的事情:给定一个文本文件,我想找到所有 Dffs 并用新名称替换它们。这里“Dffs”以“reg foo1”或“reg [3:0] foo2”之类的格式出现,但“reg”之后的内容可能是也可能不是 Dff。只有当 Dff 哈希中存在“reg foo3”和“foo3”时,foo3 才被认为是一个 Dff。文件中可能有很多Dff;我需要找到并替换它们。
  • 所以你有“reg text-to-replace”,但只有当“text-to-replace”和“reg text-to-replace”都是哈希中的键时才替换它?他们都?顺便说一句,什么是“Dff”——你使用这些东西的名字?什么是“Dff 哈希”,只是一个哈希,其中包含要操作的字符串中的键?
  • 这真的让它完全不同,一旦你更新问题,我将删除这个毫无意义的“答案”(因为我认为这些 cmets 中的解释改变了问题),如果你愿意的话。如果您想要有用的想法,我建议您这样做。
  • Sobrique 给出的答案正是我想要的。谢谢;-)
猜你喜欢
  • 2017-01-05
  • 2013-04-06
  • 2010-10-29
  • 2020-08-09
  • 1970-01-01
  • 2020-11-22
  • 2013-05-20
  • 2021-12-13
  • 2010-10-22
相关资源
最近更新 更多