混淆单引号/双引号和\\关于拆分

时间:2013-05-15 22:31:30

标签: perl

所以,我在另一篇文章中看到要使用\\作为分隔符进行拆分,您需要拆分\\\\\\\\。这对我来说没有意义,但是当我尝试使用\\\\进行拆分时,发生了这种情况:

my $string="a\\\\b\\\\c";
my @ra=split("\\\\",$string);

数组是:

a
<empty>    
b
<empty>
c

正如另一张海报所说,使用\\\\\\\\完美无缺。为什么会这样?

此外,我很好奇并开始搞砸'' vs "",并得到了意想不到的结果。我以为我明白了区别是什么,但我想我没有,至少在以下情况下没有:

my $string="a\.\.b\.\.c";
my @ra=split("\.\.",$string);

数组是:

<empty>
<empty>
<empty>
c

然而,

my $string="a\.\.b\.\.c";
my @ra=split('\.\.',$string);

数组是:

a
b
c

提前致谢。

3 个答案:

答案 0 :(得分:4)

哦,引用规则和正则表达式。

带有不同引号的反斜杠规则

  • q()及相关内容中,所有反斜杠都保留在字符串中,除非它们转义字符串分隔符或其他反斜杠:

    say '\a\\b\''; # »\a\b'«
    
  • qq()及相关内容中,所有不构成已知字符串转义序列的反斜杠都会被静默删除:

    say "\d\\b\"\."; # »d\b."«
    
  • qr//和正则表达式文字中同上,但与双引号字符串相比有不同的转义。

如果使用字符串代替正则表达式,那么在编译期间将执行该类型字符串的转义规则。但是,当它用作正则表达式时会处理第二级转义,因此在最坏的情况下反斜杠必须双重转义。正则表达式文字没有遭受这个问题;只有一个级别的逃脱。

您的示例说明

因此,"a\\\\b\\\\c";a\\b\\c"\\\\"\\,其中\与正则表达式匹配。因此它会在每个反斜杠上分割,从而在双反斜杠之间生成零长度字段。

您所指的其他问题的'\\\\\\\\'\\\\,正则表达式与\\匹配。

"a\.\.b\.\.c"a..b..c"\.\."..,正则表达式匹配两个非换行符。它首先匹配a.,然后匹配.b,然后匹配..。这会生成字符串片段"", "", "", "c"

字符串'\.\.'\.\.,正则表达式依次匹配两个文字句点。

解决方案是使用regex到期的正则表达式。 split将正则表达式作为第一个参数(如split /foo/),在其他方案中,正则表达式引用qr/foo/很有用。这避免了令人费解的 [1] 双重逃逸。

[1]:对于“心灵弯曲”的小值,一旦你遵守规则。

答案 1 :(得分:3)

  • 在单引号字符串文字中,

    • \后跟字符串分隔符(默认情况下为')会产生字符串分隔符。

      'That\'s fool\'s gold!'   -> That's fool's gold!
      q!That's fool's gold\!!   -> That's fool's gold!
      
    • \后跟\会产生\

      'c:\\foo'                 -> c:\foo
      
    • \后跟任何其他内容会产生这两个字符。

      'c:\foo'                  -> c:\foo
      
  • 在双引号字符串文字中,

    • \后跟该字符的非单词字符结果。

      "c:\\foo"                 -> c:\foo
      "Can't open \"foo\""      -> Can't open "foo"
      
    • \后跟单词字符具有特殊含义。

      "foo\n"                   -> foo{newline}
      
  • 在正则表达式文字中,

    • \后面的分隔符被替换为分隔符中的结果。

      qr/\//                    -> /
      
    • \后跟任何其他内容会产生这两个字符。

      qr/\\/                    -> \\
      qr/\_/                    -> \_
      qr/\$/                    -> \$
      qr/\n/                    -> \n
      
  • 应用正则表达式时,

    • \后跟非字符字符匹配该字符。

      /c:\\foo/                 -> Matches strings containing: c:\foo
      
    • \后跟单词字符具有特殊含义。

      /foo\z/                   -> Matches strings ending with: foo
      

查看你的案例:

 my $string="a\\\\b\\\\c";
 my @ra=split("\\\\",$string);

"\\\\"会生成字符串\\,因此您首先创建字符串a\\b\\c,然后将\\传递给split

split的第一个参数用作正则表达式,正则表达式模式\\匹配单个\\中有4个a\\b\\c,因此它会分成4 + 1个。

如果使用正则表达式文字而不是双引号字符串文字,则会减少混淆。

split(/\\/, $string);        # Passes pattern \\ to split. Matches singles
split("\\\\", $string);      # Passes pattern \\ to split. Matches singles
split(/\\\\/, $string);      # Passes pattern \\\\ to split. Matches doubles
split("\\\\\\\\", $string);  # Passes pattern \\\\ to split. Matches doubles

简而言之,请勿使用split "..."


现在你的其他两个案子应该是显而易见的。

my $string="a\.\.b\.\.c";          # String a..b..c
my @ra=split("\.\.",$string);      # Pattern .., which matches any two chars.

my $string="a\.\.b\.\.c";          # String a..b..c
my @ra=split('\.\.',$string);      # Pattern \.\., which matches two periods.

答案 2 :(得分:0)

使用/ \\\\ /而不是“\\\\”进行拆分,避免一切后顾之忧,

e.g。

use Data::Dumper;

my $string= "a\\\\b\\\\c";

my @ra = split /\\\\/, $string;

print Dumper @ra;

将输出

$VAR1 = [
          'a',
          'b',
          'c'
        ];

/ \\ /将连续匹配两个\

或者你可以很可爱并且做到

split /\\{2}/, $string