给定一串管道分隔值(称为$psv
),我希望能够通过这些管道进行拆分并填充数组。但是,该字符串还可以包含转义管道(\|
)和转义转义符(\\
),这两者都被视为仅仅是文字。我有几种解决方案可以解决这个问题:
$psv
,split(/\|/, $psv)
中找到,替换回原始字符 li>
$psv
,逐个字符我认为这两种方法都有效。但是对于最大的多巴胺泛滥,我想通过一次split()
呼叫来做这件事,而不是别的。那么这是否有正则表达式?
答案 0 :(得分:4)
您无需使用split
执行此任务。另一种选择是:
my $psv = "aaa|bbb||ccc|\\|\\|\\||\\\\\\\\\\\\";
print "$psv\n";
my @words = map { s/\\([\\|])/$1/g; $_; } ($psv =~ /(?:^|\|) ((?:\\[\\|] | [^|])*)/gx);
printf("%s\n", join(", ", @words));
正则表达式可能看起来很可怕,但很容易解释。它匹配由管道分隔的每个单词。它从字符串的开头或管道分隔符开始。然后跟随任意数量的转义序列(\
+ \|
之一)或除管道之外的任意字符。
map
中的正则表达式只是将转义序列替换为它们的真正含义。
答案 1 :(得分:4)
您是否需要纯正则表达式解决方案? (当然,除非这个问题更像是一个心理挑战,而不是一个实际问题)。
在实际代码中处理X分隔数据的正确方法是使用正确的解析器 - 一个非常常见的解析器是Text::CSV_XS
(不要让名字欺骗你 - 它可以处理任何分隔符,而不是只是逗号)。它将正确处理转义,以及引用。
答案 2 :(得分:2)
如果Perl支持可变宽度的后视断言,你可以用这样的方式来做:
split(/(?<!(?<!\\)(?:\\\\)*\\)\|/, $psv);
这应该匹配一个前面没有的管道符号(奇数个反斜杠前面没有反斜杠)。但是只允许使用固定宽度的后视断言,所以这不是一个选项。有些正则表达式专家可能会想出一些实际上适合你的东西,但我个人认为有限状态机(一次循环$psv
一个字符)可能是更好的选择。
我想你可以尝试的其他东西就是将字符串拆分为管道字符,然后检查结果列表的每个元素,看它是否以奇数个反斜杠结尾。如果是,请将它连接回列表的下一个元素,它们之间有|
。基本上你会忽略转义序列进行拆分,然后返回并计算转义后的转义。
答案 3 :(得分:0)
此方法不使用拆分,但使用简单的正则表达式。
#!/usr/bin/perl -w
use strict;
sub main{
(my $psv = <DATA>) =~ s/\s+$//s;
my @arr = $psv =~ /(?:^|\G\|)((?:[^\\|]|\\.)*)/sg;
{
local $" = ', '; # $" - sets the pretty print
print "@arr \n"; # outputs: abc, def, g\|i, jkl, m\|o, pqr, s\\u, v\w, x\\, , z
}
}
main();
__DATA__
abc|def|g\|i|jkl|m\|o|pqr|s\\u|v\w|x\\||z