如何将转义字符转换为Perl中的实际特殊字符?

问题描述:

可能重复:
How can I manually interpolate string escapes in a Perl string?如何将转义字符转换为Perl中的实际特殊字符?

我读从一个特定的文件中的字符串。它的问题是它包含转义字符,如:

Hello!\nI\'d like to tell you a little \"secret\"... 

我想它打印出来,而不转义序列,如:

Hello! 
I'd like to tell you a little "secret". 

我考虑去除单反斜线和更换双倍于单个(因为\被表示为\\),但是这对我\ n,\ t问题等没有帮助。在试图摆弄丑陋,复杂的替换字符串之前,我想我会问 - 也许Perl有这种转换的内置机制?

在Perl单个字符backslash escapes,你可以这样做安全使用两个字符eval作为替代的一部分。您需要在\之后放入可接受的字符类中解释的字符,然后是eval'd后面的单个字符并插入到字符串中。

考虑:

#!/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部分确实对替换字符串的双重EVAL。

  • "qq|\\$1|"部分eval'd两次。第一个eval$1替换为字符串,第二个执行插值。

我想不出一个两个字符的组合,这将是一个安全漏洞...

这种方法确实处理正确执行以下操作:

  • 带引号的字符串。例如,由于单引号,Perl不会忽略字符串'line 1 \ nline 2'。

  • 逃逸序列,其比单个字符较长,如十六进制\x1b或Unicode如\N{U+...}或控制序列,例如\cD

  • 锚逃逸,如\ LMAKE小写\ 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除了:

  1. 锚型(\ Q,\ü通过。\ E结束,\ L)

  2. 引用形式,如'don't \n escape in single quotes'[not \n in here]

  3. 命名为unicode字符,如\N{THAI CHARACTER SO SO}

  4. 控制字符如\cD(即容易加到...)

但是,这不是你的问题的一部分,因为我的理解是......

+0

第一次替换效果很好,谢谢! – Neo 2010-10-03 15:44:30

我不建议这样做,但字符串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 [email protected]; 
    print $string; 
} 

__DATA__ 
Hello!\nI\'d like to tell you a little \"secret\". 
This is bad @{[print "I have pwned you\n"]}. 

另一个解决方案是创建一个哈希定义所有你想要实现和做一个替代的逃逸。

+0

这是一个本地应用程序,命令行脚本,用于从其他一些工具分析日志文件。在那种情况下,我认为eval不会成为安全漏洞的重要部分,对吧? – Neo 2010-10-02 12:03:03

+0

您是否在评估日志文件中的内容?如果是这样,数据如何进入日志文件?如果用户所需要做的就是制作正确的信息来破坏或破坏你的代码,那么他们会这样做。更好的选择是修复正在编写日志文件的人以使用转义特殊字符的标准化方法,如RFC 3986中的特殊字符(即URI转义)。 – 2010-10-02 12:08:47

+0

试试这个安全。 – muhmuhten 2010-10-02 21:05:52