【问题标题】:How to change a pattern like XX1/XXSomething/XX1/Something to XXSomething/XX1/Something in perl如何在perl中将XX1/X Something/XX1/Something之类的模式更改为Something/XX1/Something
【发布时间】:2019-10-02 04:59:37
【问题描述】:

我有一个文件,其中一些行有一些模式,如

M1/XX2/XX1 XX2/XX1/XX2/WCLKB XX2/XX1/XX2/P001  
M1/XX4/XX5 XX4/XX5/XX4/WCLKB XX4/XX5/XX4/P001

这里在某些模式中 XX2 是重复的。我需要将上面的行更改为

M1/XX2/XX1 XX1/XX2/WCLKB XX1/XX2/P001
M1/XX4/XX5 XX5/XX4/WCLKB XX5/XX4/P001

这些 XX 可以变化 XX[0..9] 代码在 Perl 中。

我尝试使用一些正则表达式但很困惑。

 open(FILE,$FilePath);
 @linesInFile = <FILE>;
 close(FILE);
 foreach $item(@linesInFile){
    if(grep(/^XX?\/XX.\/XX)
  #I dont know how to complete this 
}

【问题讨论】:

  • 作为一个新的 SO 用户,我建议你阅读How to ask,特别是How to create a Minimal, Complete, and Verifiable example,这样它可以帮助其他人,反过来他们也可以帮助你,否则你的帖子可能会被否决(虽然我没有对你的帖子投反对票)并关闭了。
  • 那么如果一个单词以XX[0..9]/ 开头,你想从单词中删除那部分吗?

标签: regex perl pattern-matching file-handling regex-negation


【解决方案1】:

根据您在问题描述XX[0..9] 中的解释,以下perl 命令应该可以解决问题:

输入:

$ cat input
M1/XX2/XX1 XX2/XX1/XX2/WCLKB XX2/XX1/XX2/P001  
M1/XX4/XX5 XX4/XX5/XX4/WCLKB XX4/XX5/XX4/P001

命令:

perl -pe 's@\bXX(\d)/XX(\d)/XX\1@XX$2/XX$1@g' input

输出:

M1/XX2/XX1 XX1/XX2/WCLKB XX1/XX2/P001  
M1/XX4/XX5 XX5/XX4/WCLKB XX5/XX4/P001

【讨论】:

  • 替换部分中应该是$2$1(另请参见perl -w)。
  • 请注意(默认情况下)\d 不仅仅匹配 [0-9]。它匹配任何具有“数字”属性的 Unicode 字符。
  • @melpomene:谢谢我已经相应地编辑了我的答案。事实上[0-9] 在这场比赛中可能更安全。
  • @melpomene, Re "请注意(默认情况下)\d 不仅仅匹配 [0-9]",除非您使用 -CI(或等效项)或use feature qw( unicode_strings );(或等效)或/u(或等效),它不会。并且很容易使用/a强制匹配0-9。
  • @ikegami:感谢您选择这个!我已经通过添加积极的后视来编辑我的答案,也感谢您的编辑!剩下的就是我们如何解释这个问题了
【解决方案2】:

如果您专门寻找XXn/XXm/XXn/(其中n 两次都是相同的数字),您可以使用反向引用:

s{(XX[0-9]+/)(XX[0-9]+/\1)}{$2}g

这里的\1 引用并匹配与第一个捕获组(XX[0-9]+/) 相同的字符串。

Live demo:

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

while (my $line = readline DATA) {
    $line =~ s{(XX[0-9]+/)(XX[0-9]+/\1)}{$2}g;
    print $line;
}

__DATA__
M1/XX2/XX1 XX2/XX1/XX2/WCLKB XX2/XX1/XX2/P001
M1/XX4/XX5 XX4/XX5/XX4/WCLKB XX4/XX5/XX4/P001

输出:

M1/XX2/XX1 XX1/XX2/WCLKB XX1/XX2/P001
M1/XX4/XX5 XX5/XX4/WCLKB XX5/XX4/P001

【讨论】:

  • 我们也可以考虑在我们的正则表达式中使用\b 单词边界!无论如何+1。
  • 请注意,这会将ZXX1/XX2/XX1/b 更改为ZXX2/XX1/b
【解决方案3】:

如果盲目删除第一部分也可以:

while (<>) {
   s{ \K[^\s/]+/}{}g;
   print;
}

作为单行:

perl -pe's{ \K[^\s/]+/}{}g'

如果您想确保它与您指定的模式匹配:

while (<>) {
   s{(?<!\S)(XX\d)/(?=XX[^\s/]+/\1/\S)}{}ag;
   print;
}

作为单行:

perl -pe's{(?<!\S)(XX\d)/(?=XX[^\s/]+/\1/\S)}{}ag'

密钥是\1,意思是“匹配第一次捕获的内容”。

【讨论】:

  • 第一个匹配每个包含斜杠(但不以斜杠开头)的单词,并删除第一个斜杠之前(包括)之前的部分。
  • @melpomene,是的。这就是“一味去掉第一部分”的意思。
猜你喜欢
  • 2013-03-11
  • 2020-09-30
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 2013-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多