【问题标题】:perl regex, remove what is capturedperl 正则表达式,删除捕获的内容
【发布时间】:2021-08-18 09:01:26
【问题描述】:

我已经用这个成功捕获了数据:

/^.{144}(.{15}).{34}(.{1})/

结果如下:

TTGGCCCCCACTCTC T

我想从相同的位置删除相同的字符。我尝试了一个简单的替换:

s/^.{144}(.{15}).{34}(.{1})//

这将删除所有描述的内容。如何仅删除 (...)?

【问题讨论】:

  • 同时捕获其他部分,以便能够用您想要保留的部分替换整个匹配项:s/^(.{144})(.{15})(.{34})(.)/$1$3/。或者,您可以“删除”第一个匹配项(使用\K),这样您就不必将其放回:s/^(.{144})\K(.{15})(.{34})(.)/$3/。如果您不需要要删除的东西(例如打印它们或存储在其他地方),则省略它们的捕获括号——它们不需要为了匹配,s/^.{144}\K.{15}(.{34})./$1/
  • 文档:教程perlretut,完整参考perlre。还有一些其他页面
  • 仍然卡住。在执行任何一次传递之前,我需要确定要保留的组,在本例中为 $keep = "$1$3$5"。但是 s/.../$keep/ 导致整个记录被文字替换。数据、组等随着每次迭代而变化。我无法事先知道(将近一百万条记录)我需要什么。迷路了。
  • 我不明白这个问题。因此,在您运行正则表达式(每个组都由 () 捕获的版本)$v =~ s/.../.../; 之后,您在 $1 中拥有 144 个字符,在 $2 中拥有接下来的 15 个字符(这已从 $v 中删除)然后 $3 中的 34 个字符,然后 $4 中的 1 个字符(从 $v 中删除)。然后,如果您需要其余部分并添加(.+),则位于$5(保留)中。你用你需要的东西去做,在下一次迭代中(我认为是某个循环),无论$var中的任何新内容都会重新发生......这个故事有什么问题?
  • 等等 --- 如果你的意思是你字面上写 $keep = '$1$2$3' 然后在正则表达式中使用 $keep (需要单引号)......不能那样做。是这个意思吗?

标签: regex perl match


【解决方案1】:

替代的工作方式

s/match/replace/

所以它将用“替换”替换你的完整“匹配”。如果要保留部分匹配,则必须在替换字符串中设置组的引用。

s/^.{144}(.{15}).{34}(.{1})//     # replace all with nothing
s/^.{144}(.{15}).{34}(.{1})/$1/   # replace all with group 1 (.{15}) -> not what you want
s/^(.{144}).{15}(.{34}).{1}/$1$2/ # keeps group 1 and 2 and removes ".{15}" between them and all at the end.

你需要的最后一个。

试试regex101。在那里你可以给出一个模式,它会显示你的组。还有一个调试器。

【讨论】:

  • 谢谢!该页面对可视化这一点有很大帮助。我对所有内容进行了分组,包括用 (.+) 表示的最后一个块。我用 /$1$3$5/ 保留了我需要的东西,然后删除了 $2 和 $4。正是我想要的!
  • @MichaelCooley 在 Stackoverflow 上“谢谢”== 点赞并接受。见What should I do when someone answers my question?(但我认为一个不错的评论也可以:)
  • 对于正则表达式的可视化,我也喜欢debuggex.com
【解决方案2】:

正则表达式中的替换端被替换而不是匹配的所有内容(虽然有一些方法可以在某种程度上改变它),所以您需要捕获打算保留的东西,并将它们放回替换中边。喜欢

$var =~ s/^(.{144})(.{15})(.{34})(.)(.*)/$1$3$5/;

(最后一次捕获已添加到评论中)或

$var =~ s/^(.{144})\K(.{15})(.{34})(.)(.*)/$3$5/;

现在 15 个字符和单个字符已从 $var 中删除,而您仍然可以根据需要使用所有 $N (1--5)。 (在第二个版本中,\K keeps 之前的所有匹配项,因此它们不会被替换,因此我们不需要 $1 在替换端。)请参阅@ 987654321@了解详情。

但是,正如评论启发我们的那样,这样做有一个问题:在运行之前不知道需要保留哪些组!所以它可能是 1,3,5 或者可能是 2 和 4(或 7 和 11?)。

在正则表达式运行之前,需要保留的内容变得已知并需要设置。

一种方法:一旦知道要保留的捕获组列表,将它们的索引存储在一个数组中,然后将所有匹配项捕获到一个数组中 并形成替换并重写字符串手

my @keep_idx = qw(0 2 4);  # indices of capture groups to keep

my @captures = $var =~ /^(.{144})(.{15})(.{34})(.)(.*)/;

# Rewrite the variable using only @keep_idx -indexed captures
$var = join '', grep { defined } @captures[@keep_idx];

# Use @captures as needed...

上面的代码只是通过grep 过滤任何可能不存在的“捕获”——一种模式可能允许可变数量的捕获组(例如,可能不存在组#5)。但我宁愿明确检查那些@captures(是否有预期的那么多?它们都是预期的形式吗?等等)。

还有其他方法可以做到这一点。


在较新的 perls(从版​​本 5.25.7 开始)中,@{^CAPTURE} predefined variable 包含所有捕获,因此可以运行匹配 $var =~ /.../; 然后使用它。无需分配捕获。


我想提一种可能很诱人的方式,可以在周围看到,但最好避免。

一个可以为替换端形成一个字符串并对其进行双重评估,就像这样

my $keep = q($1.$3.$5);  # perl *code*, concatenating variables

$var =~ s/.../$keep/ee;  # DANGEROUS. Runs any code in $keep

这里的修饰符/ee 评估右侧,并且以一种将程序暴露给评估可能已经滑到它的代码(在$keep 中)的方式。搜索此以获取更多信息,但我会说最好不要在重要的地方使用它。

【讨论】:

    【解决方案3】:

    感谢大家的帮助。我不明白 cmets 是如何工作的,并一直在整理它们。我决定最干净(如果不是最优雅)的方法是创建两个模式。我正在保留其他解决方案以供将来学习。这是一个不同的例子,

    我要记下的数据列表,然后删除:

    /.{41}.{24}(\D{4}).{63}.{16}(\D{2}).{22}.{228}/
    

    我想保留的数据:

    /(.{41})(.{24})\D{4}(.{63})(.{16})\D{2}(.{22})(.{228})/
    

    我正在处理的是遗传数据。我需要记下插入然后删除它们以重新建立原始位置以进行对齐。

    如果我理解正确,我需要投票结束。像我这样的白痴只能做他能做的事。我会尽力。 :)

    【讨论】:

    • 对不起。我找不到“upvote”。我已经好几年没上这个网站了。
    • 点击分数上方文本左侧的灰色“箭头”即可“点赞”答案,可以对任何和所有答案进行投票;我建议始终这样做,对所有对您有用的答案进行投票。您不能对自己的答案进行投票。通过单击该答案文本左侧的灰色复选标记,您“接受”其中一个答案(根据您的评估,该答案最能回答您的问题)。你可以接受你自己的答案,如果那个答案最能回答你的问题。
    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    相关资源
    最近更新 更多