【问题标题】:How to replace the characters in substring, including escape characters, with the character 'X'?如何用字符'X'替换子字符串中的字符,包括转义字符?
【发布时间】:2015-09-13 02:27:34
【问题描述】:

我想替换 perl 脚本中给定字符串(包括转义字符)中的子字符串(包括转义字符)。如果可能的话,使用正则表达式。

输入:

abcdefg hijkl: (mnop-qrst) uvwx
aabbccd deeff: (gghh-iijj) kkll
aaabbbc ccddd: (eeef-ffgg) ghhh

替换字符串示例:

ijkl:
gghh-iijj
ccddd: (eeef-ffgg)

输出:

abcdefg hXXXX: (mnop-qrst) uvwx
aabbccd deeff: (XXXX-XXXX) kkll
aaabbbc XXXXX: (XXXX-XXXX) ghhh

除了文章“有没有办法用与它的长度相同数量的 X 字符替换子字符串?”文章之外我没有找到任何东西,但是没有转义字符。
正则表达式 $s =~ s/(\Q$pattern\E)/'X' x length $1/e; 适用于任何字母数字替换字符串,但如果它包含特殊字符(如 ()=,.-:;*)则不适用

在上面的示例中,输入字符串和替换字符串都可以包含特殊字符。

【问题讨论】:

  • 好的,您已经指定了替换字符串(eeef-ffgg) - 但希望将其替换为(XXXXXXXXX)?所以我认为您想要对括号中的内容进行不同的处理?
  • 我有一个给定的替换字符串“ccddd: (eeef-ffgg)”。如果文本是“aadd: (eeef-ffgg)”之类的其他内容,则不应替换任何内容。括号中的内容没有特别的威胁。我只想让 perl 在一个输入行中查找完全相同的替换字符串。如果找到结果,它应该用 X 替换除特殊字符和空格之外的任何内容。
  • @lycos:你怎么称呼`特殊字符?为什么ccddd: (eeef-ffgg)XXXXX: (XXXXXXXXX) 而不是XXXXX: (XXXX-XXXX) 取代?为什么括号和冒号是特殊的,而连字符不是?除了字母和数字之外还有什么不是特殊的吗?
  • @Borodion:连字符也应该是特殊字符。我更正了上面的例子。

标签: regex perl escaping substring


【解决方案1】:

我建议的技巧是预先生成您的正则表达式模式。

use strict;
use warnings;


my @replace_strings = qw ( ijkl:
    mnop-qrst
    hijkl: );

my %replace = map { $_ => "X" x length($_) } @replace_strings;

my $replace_regex = join( "|", map {quotemeta} @replace_strings );
$replace_regex = qr/($replace_regex)/;

while (<DATA>) {
    s/$replace_regex/$replace{$1}/g;
    print;
}

 __DATA__
 abcdefg hijkl: (mnop-qrst) uvwx

我们:

  • 使用“替换字符串”列表。
  • 使用映射生成替换(X x 长度)
  • 生成正则表达式以匹配“搜索”
  • 然后使用它来应用“替换”

这样打印出来:

abcdefg XXXXXX (XXXXXXXXX) uvwx

您可以使用类似的技术。

从 cmets 开始 - 看起来您想要定义一些字符串,然后替换其中的文本。

那么这样的事情怎么样:

my %replace = map { $_ => ($_ =~ s/\w/X/gr) } @replace_strings;

哪个(根据您的源数据)给出:

abcdefg hXXXX: (mnop-qrst) uvwx
aabbccd deeff: (XXXX-XXXX) kkll
aaabbbc XXXXX: (XXXX-XXXX) ghhh

(如果您也想替换它,可以将- 添加到模式中)。

【讨论】:

  • 这也将替换转义字符。有没有不删除转义字符的解决方案?如果您使用此输入数据: DATA abcdefg hijkl: (mnop-qrst) uvwx aabbccd deeff: (gghh-iijj) kkll aaabbbc ccddd: (eeef-ffgg) ghhh 并替换字符串:ijkl: gghh -iijj ccddd: (eeef-ffgg) );
  • quotemeta 位应该会为您解决这个问题。它转义特殊字符以在您的正则表达式中使用。但如果它要替换 just 字母,那么 tr 应该可以完成这项工作。
  • 我编辑了上面的例子来进一步描述它。当我使用包含quotemeta位的示例时,最后一行看起来像这样 aaabbbc XXXXXX XXXXXXXXXXX ghhh 而不是 aaabbbc XXXXX: (XXXXXXXXX) ghhh。
  • 那个看起来怎么样?
  • 效果很好。是否有可能在不匹配空格数量的情况下使其工作?如果替换字符串例如值之间有多个空格或空格少于输入?
【解决方案2】:

更新

这是一个解决方案,它允许模式中的任何空格匹配目标字符串中的任意数量的空格。请注意,为此,我必须手动转义非单词字符,因此不再需要 \Q...\E

请注意,最后一个模式在 ccddd:(eeef-ffgg) 之间有很多空格,但它正确匹配字符串中的单个空格

use strict;
use warnings;

my @patterns = (
  'ijkl:',
  'gghh-iijj',
  'ccddd:            (eeef-ffgg)',
);

# Build and compile the regex
my $pattern = join '|', map {
  my $item = $_;
  $item =~ s/([^\w\s])/\\$1/g;
  $item =~ s/\s+/\\s+/g;
  $item;
} @patterns;
$pattern = qr/$pattern/;

while ( my $s = <DATA> ) {
  $s =~ s/($pattern)/$1 =~ tr{a-zA-Z0-9}{X}r/eg;
  print $s;
}

__DATA__
abcdefg hijkl: (mnop-qrst) uvwx
aabbccd deeff: (gghh-iijj) kkll
aaabbbc ccddd: (eeef-ffgg) ghhh

输出

abcdefg hXXXX: (mnop-qrst) uvwx
aabbccd deeff: (XXXX-XXXX) kkll
aaabbbc XXXXX: (XXXX-XXXX) ghhh

原帖

只需要替换

s/(\Q$pattern\E)/'X' x length $1/e

s/(\Q$pattern\E)/$1 =~ tr{a-zA-Z0-9}{X}r/e

这是一个演示。请注意,/r 修饰符需要 Perl v5.14 或更高版本

use strict;
use warnings;
use 5.014;

my @matches = (
  'ijkl:',
  'gghh-iijj',
  'ccddd: (eeef-ffgg)',
);

while ( my $s = <DATA> ) {
  $s =~ s/(\Q$_\E)/$1 =~ tr{a-zA-Z0-9}{X}r/e for @matches;
  print $s;
}

__DATA__
abcdefg hijkl: (mnop-qrst) uvwx
aabbccd deeff: (gghh-iijj) kkll
aaabbbc ccddd: (eeef-ffgg) ghhh

输出

abcdefg hXXXX: (mnop-qrst) uvwx
aabbccd deeff: (XXXX-XXXX) kkll
aaabbbc XXXXX: (XXXX-XXXX) ghhh

【讨论】:

    猜你喜欢
    • 2016-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2019-05-08
    • 1970-01-01
    • 2017-03-23
    相关资源
    最近更新 更多