这与Perl FAQ 的第 4 节中的一个常见问题有关。
除非在 [character] 内,否则如何拆分 [character] 分隔的字符串?
有几个模块可以处理这种解析—— Text::Balanced、Text::CSV、Text::CSV_XS和Text::ParseWords等等。
以尝试将逗号分隔的字符串拆分为不同字段的示例为例。您不能使用split(/,/)
,因为如果逗号在引号内,您不应该拆分。例如,采用这样的数据线:
SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"错误,核心转储"
由于引号的限制,这是一个相当复杂的问题。值得庆幸的是,我们有Mastering Regular Expressions的作者 Jeffrey Friedl为我们处理这些问题。他建议(假设您的字符串包含在 中$text
):
my @new = ();
push(@new, $+) while $text =~ m{
# groups the phrase inside the quotes
"([^\"\\]*(?:\\.[^\"\\]*)*)",?
| ([^,]+),?
| ,
}gx;
push(@new, undef) if substr($text,-1,1) eq ',';
如果您想在引号分隔的字段中表示引号,请使用反斜杠(例如,"like \"this\""
)转义它们。
或者,Text::ParseWords模块(标准 Perl 发行版的一部分)让您说:
use Text::ParseWords;
@new = quotewords(",", 0, $text);
但是,对于解析或生成 CSV,强烈建议使用Text::CSV而不是自己实现它;您只需使用已经在生产环境中尝试和测试多年的代码,就可以避免以后出现的奇怪错误。
使该技术适应您的情况
my $htmlVal = 'word "word word" word';
my @chunks;
push @chunks, $+ while $htmlVal =~ m{
"([^\"\\]*(?:\\.[^\"\\]*)*)"
| (\S+)
}gx;
$htmlVal = join "||", @chunks;
print $htmlVal, "\n";
输出:
单词||单词单词||单词
回顾过去,事实证明这是 Randal 规则的一个应用,正如Mark Dominus在Regular Expression Mastery中所说的那样:
兰德尔法则
使用捕获或m//g
当您知道要保留什么时。
split
当您知道要丢弃什么时使用。
在您的情况下,您知道要保留什么,因此请使用m//g
引号内的文本或以空格分隔的其他文本。