2017-02-21 143 views
0

我有以下函數將unicode轉換爲HTML實體,但是如果我再次對結果運行該函數,它將不會使HTML實體處於機智狀態。我怎樣才能讓函數離開已經轉換的HTML實體?將unicode轉換爲HTML實體功能

sub convert_unicode { 
    use HTML::Entities; 
    use Encode; 
    my $str = shift; 
    Encode::_utf8_off($str); 
    return encode_entities(decode('utf8',$str)); 
} 
+2

您是否要求'encode_entities(encode_entities(「&foo」))'返回'& foo'而不是'& amp; foo'?如果是這樣,那不是處理編碼的好方法。編碼*一次*。 – Schwern

+0

@Schwern我可能會在字符串上多次運行我的整個函數,而且我希望它只保留現有的HTML實體。 – CJ7

+1

沒有理由在subs中放置(non-pragma)'use'語句。 – ikegami

回答

3

你要求的是能夠安全地加倍字符編碼。一些編碼允許這樣做。 HTML字符編碼並不是因爲它使用某些字符如&來進行編碼,而且它不能區分用於編碼的特殊字符和需要編碼的特殊字符之間的區別。

例如...

use HTML::Entities; 
use v5.10; 
say encode_entities("&foo"); 

產生&foo。如果我們再次編碼它會產生&foo,因爲&是一個特殊的字符,它忠實地編碼。 它不知道&是一個已經編碼的&所以它把它當作文字&並對它進行編碼。

可能編寫您自己的自定義HTML編碼函數,假設&xxx;(及其變體)已被編碼,但這只是一個猜測。除了文字&foo;和編碼&foo;之外,你實際上不能說出。例如,它將與例如舊學校的Perl代碼(如&function;)打破。也許你可以超級聰明並使用一個對象數組來指示哪些部分被編碼,並讓整個事物超負荷化,所以它看起來像一個字符串,只要所有的東西都小心地保留那個看起來像一個字符串的對象,我會努力...

現在我們進入lava flow anti-pattern而不是修復壞的設計,更復雜和糟糕的設計是分層的。試圖「修復」這隻會造成更多的問題。真正的問題在於更深層次。


真正的問題是你要多次編碼。這可能意味着你已經將你的格式和功能一起使用。例如...

sub get_user_name { 
    my $uid = shift; 

    my $name = ...do a bunch of work to get the user name... 

    return encode_entities($name); 
} 

通過對數據進行HTML編碼,像這樣的函數就會假設數據將如何被使用。它將它的使用限制在HTML中。如果你所有的功能都這樣做,你就會遇到雙重編碼問題。

,那麼也許你有這樣的事情:

sub do_something { 
    my $uid = shift; 

    # $name is already HTML encoded. 
    my $name = get_user_name($uid); 

    my $stuff = ...something incorporating $name... 

    # Whoops, the user name is double encoded. 
    return encode_entities($stuff); 
} 

答案是離開HTML格式和編碼,直到最後一分鐘。理想情況下,根本不要這樣做,只需處理數據並讓HTML模板系統處理它。例如,Template Toolkit

這也提供了格式化和代碼之間的清晰分離,所以現在非程序員可以使用文檔化的模板系統來處理格式化。