可能重复:
How can I manually interpolate string escapes in a Perl string?
我正在读取特定文件中的字符串。它的问题在于它包含转义字符,例如:
Hello!\nI\'d like to tell you a little \"secret\"...
我希望它在没有转义序列的情况下打印出来,例如:
Hello!
I'd like to tell you a little "secret".
我考虑过删除单个反斜杠并用单个替换double(因为\表示为\\),但这对我没有帮助\ n,\ t问题等等。在试图摆弄丑陋,复杂的替换字符串之前,我想我会问 - 也许Perl有这种转换的内置机制?
答案 0 :(得分:4)
对于Perl单个字符backslash escapes,您可以使用两个字符eval
作为替换的一部分安全地执行此操作。您需要在\
之后插入可在字符类中解释的字符,然后在eval
之后插入单个字符并插入字符串中。
考虑:
#!/usr/bin/perl
use warnings;
use strict;
print "\n\n\n\n";
while (my $data = <DATA>) {
$data=~s/\\([rnt'"\\])/"qq|\\$1|"/gee;
print $data;
}
__DATA__
Hello!\nI\'d like to tell you a little \"secret\".
A backslask:\\
Tab'\t'stop
line 1\rline 2 (on Unix, "line 1" will get overwritten)
line 3\\nline 4 (should result in "line 3\\nline 4")
line 5\r\nline 6
输出:
Hello!
I'd like to tell you a little "secret".
A backslask:\
Tab' 'stop
line 2 (on Unix, "line 1" will get overwritten)
line 3\nline 4 (should result in "line 3\nline 4")
line 5
line 6
行s/\\([rnt'"\\])/"qq|\\$1|"/gee
完成工作。
\\([rnt'"\\])
在大括号内有可接受的字符值。
gee
部分对替换字符串执行双重评估。
"qq|\\$1|"
部分被评估两次。第一个eval
将$1
替换为字符串,第二个执行插值。
我想不出这里会出现安全漏洞的两个字符组合......
此方法不正确处理以下内容:
引用字符串。例如,由于单引号,Perl不会取消字符串'line 1 \ nline 2'。
转义超过单个字符的序列,例如十六进制\x1b
或Unicode(例如\N{U+...}
)或控制序列(例如\cD
锚定转义,例如\ LMAKE LOWER CASE \ E或\ Umake大写\ E
如果您想要更完整的转义替换,可以使用此正则表达式:
#!/usr/bin/perl
use warnings;
use strict;
print "\n\n\n\n";
binmode STDOUT, ":utf8";
while (my $data = <DATA>) {
$data=~s/\\(
(?:[arnt'"\\]) | # Single char escapes
(?:[ul].) | # uc or lc next char
(?:x[0-9a-fA-F]{2}) | # 2 digit hex escape
(?:x\{[0-9a-fA-F]+\}) | # more than 2 digit hex
(?:\d{2,3}) | # octal
(?:N\{U\+[0-9a-fA-F]{2,4}\}) # unicode by hex
)/"qq|\\$1|"/geex;
print $data;
}
__DATA__
Hello!\nI\'d like to tell you a little \"secret\".
Here is octal: \120
Here is UNICODE: \N{U+0041} and \N{U+41} and \N{U+263D}
Here is a little hex:\x50 \x5fa \x{5fa} \x{263B}
lower case next char \lU \lA
upper case next char \ua \uu
A backslask:\\
Tab'\t'stop
line 1\rline 2 (on Unix, "line 1" will get overwritten)
line 3\\nline 4 (should result in "line 3\\nline 4")
line 5\r\nline 6
除了处理所有Perl escapes之外:
锚定类型(\ Q,\ U,\ L以\ E结尾)
引用的表单,例如'don't \n escape in single quotes'
或[not \n in here]
命名的unicode字符,例如\N{THAI CHARACTER SO SO}
控制\cD
等字符(很容易添加......)
但这不是你问题的一部分,因为我明白了......
答案 1 :(得分:3)
我讨厌建议这一点,但字符串eval
可以解决问题,但字符串eval
会带来一系列安全和维护问题。这些数据来自哪里?数据生产者之间是否有任何关于字符串将保留的内容的合同?
#!/usr/bin/perl
use strict;
use warnings;
while (my $input = <DATA>) {
#note: this only works if # is not allowed as a character in the string
my $string = eval "qq#$input#" or die $@;
print $string;
}
__DATA__
Hello!\nI\'d like to tell you a little \"secret\".
This is bad @{[print "I have pwned you\n"]}.
另一种解决方案是创建一个哈希,定义您要实现的所有转义并进行替换。