2010-10-02 138 views
4

可能重複:
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有這種轉換的內置機制?

回答

3

在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

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 [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