Regex 正则表达式替换在perl中是如何工作的?

Regex 正则表达式替换在perl中是如何工作的?,regex,perl,Regex,Perl,我已尝试从字符串中删除重复项,“a”、“b”、“b”、“a”、“c”,删除后的结果是“a”、“b”、“c”。我已经做到了这一点,但我对正则表达式替代的工作有怀疑 use warnings; use strict; my $s = q+"a","b","b","a","c"+; $s=~s/ ("\w"),? / ($s=~s|($1)||g)?"$1,":"" /xge; #^ ^ #| Consider this as

我已尝试从字符串中删除重复项,
“a”、“b”、“b”、“a”、“c”
,删除后的结果是
“a”、“b”、“c”
。我已经做到了这一点,但我对正则表达式替代的工作有怀疑

use warnings;
use strict;
my $s = q+"a","b","b","a","c"+;

 $s=~s/ ("\w"),? / ($s=~s|($1)||g)?"$1,":"" /xge;
#^                   ^
#|                   Consider this as s2
#Consider this as s1

print "\n$s\n\n";
s1
值包含字符串,如
“a”、“b”、“b”、“a”、“c”

第一步

替换后:

猜猜看,以下
“a”、“b”、“b”、“c”或
“a”、“b”、“b”、“a”、“c”或
“b”、“b”、“a”、“c”或
,“b”、“b”、“c”
数据中的
s1
变量是什么

我已经用eval分组运行了正则表达式

$s=~s/ ("\w"),? (?{print "$s\n"})/ ($s=~s|($1)||g)?"$1,":"" /xge;
结果是

"a","b","b","a","c"
,"b","b",,"c"  #This is from after substitution
,,,,"c"
,,,,"c"
,,,,"c"
现在我的dobut是
s2
变量,也是
$s
为什么它没有与
s1
连接,这意味着在第二步,结果应该是
“a”、“b”、“b”、“c”
(所有字符串
“a”
都被替换为空,并且
a
被添加到
$s


已编辑

eval分组的结果是
(?{print$s})

在替换行之后,我打印了
$s
变量,它给出了
“a”、“b”、“c”
,这个输出是如何产生的。

在我看来,正则表达式是这里使用的错误工具。我会的

  • split
    逗号上的字符串
  • 从剥离返回的列表中删除重复项
  • 将列表重新连接成字符串
像这样:

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my $str = q["a","b","b","a","c"];

my %seen;

$str = join ',',
       grep { ! $seen{$_}++ }
       split /,/, $str;

say $str;
在我看来,正则表达式是这里使用的错误工具。我会的

  • split
    逗号上的字符串
  • 从剥离返回的列表中删除重复项
  • 将列表重新连接成字符串
像这样:

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my $str = q["a","b","b","a","c"];

my %seen;

$str = join ',',
       grep { ! $seen{$_}++ }
       split /,/, $str;

say $str;

正如@Dave Cross已经演示的那样,正确的解决方案是拆分、过滤和重新加入

然而,下面的正则表达式解决方案确实有效,并有望证明Dave的解决方案的优越性

#!/usr/bin/env perl

use v5.10;
use strict;
use warnings;

my $str = q{"a","b","b","a","c"};

1 while $str =~ s{
    \A
    (?: (?&element) , )*
    ( (?&element) )           # Capture in \1
    (?: , (?&element) )*
    \K
    ,
    \1                        # Remove the duplicate along with preceding comma
    (?= \z | , )

    (?(DEFINE)
        (?<element>
            "
            \w
            "
        )
    )
}{}xg;

say $str;

正如@Dave Cross已经演示的那样,正确的解决方案是拆分、过滤和重新加入

然而,下面的正则表达式解决方案确实有效,并有望证明Dave的解决方案的优越性

#!/usr/bin/env perl

use v5.10;
use strict;
use warnings;

my $str = q{"a","b","b","a","c"};

1 while $str =~ s{
    \A
    (?: (?&element) , )*
    ( (?&element) )           # Capture in \1
    (?: , (?&element) )*
    \K
    ,
    \1                        # Remove the duplicate along with preceding comma
    (?= \z | , )

    (?(DEFINE)
        (?<element>
            "
            \w
            "
        )
    )
}{}xg;

say $str;

检查正则表达式并推断它应该做什么是相当困难的,可能将其拆分为多行并为每个块添加注释,也许其他人会努力投入一些时间来解决您的问题。在我看来,您的问题来自正则表达式中的空格。如果您尝试
$s=~s/(“\w”)/_/G打印“\n将\$1替换为\$s后重试”
,您会注意到字符串没有更改,但是如果删除空格,您将得到
$s=~s/(“\w”),?/\ug
然后,
$1
将被
\uU
替代。我认为
re
模块中有用于调试的模块。有趣的是,使用
e
标志揭示
s
命令的精确语义,但该代码不可读,我会将其丢弃,以支持更可读的方法。同样的事情也适用于
$s ~
的初始化:这很难理解,所以最好使用一个大家都知道的表单。检查正则表达式并推断它应该做什么非常困难,也许将其拆分为多行,并为每个块添加注释,也许其他人会努力投入一些时间来解决您的问题。在我看来,您的问题来自正则表达式中的空格。如果您尝试
$s=~s/(“\w”)/_/G打印“\n将\$1替换为\$s后重试”
,您会注意到字符串没有更改,但是如果删除空格,您将得到
$s=~s/(“\w”),?/\ug
然后,
$1
将被
\uU
替代。我认为
re
模块中有用于调试的模块。有趣的是,使用
e
标志揭示
s
命令的精确语义,但该代码不可读,我会将其丢弃,以支持更可读的方法。同样的事情也适用于
$s ~
的初始化:这很难理解,所以最好使用一个大家都清楚的表单。谢谢你的回答。在使用正则表达式之前,我尝试过使用散列,但结果是,数据被洗牌,所以我转向正则表达式。现在你的答案解决了我的散列洗牌问题。但是我很想知道正则表达式替换是如何工作的。谢谢你的回答。在使用正则表达式之前,我尝试过使用散列,但结果是,数据被洗牌,所以我转向正则表达式。现在你的答案解决了我的散列洗牌问题。但我很想知道正则表达式替换是如何工作的。