程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> JavaEye3.0開發手記之二 - rails的UTF-8支持造成的正則表達式問題

JavaEye3.0開發手記之二 - rails的UTF-8支持造成的正則表達式問題

編輯:關於JAVA

rails的ActionView::Helpers::TextHepler模塊提供了很多實用的方法,這些方法對於論壇類應用非 常有用,例如 auto_link這個方法可以自動檢測傳入字符串當中的URL,並將其自動轉換為HTML超鏈接格 式,這對於顯示帖子的內容來說很不錯。

但是在開發JavaEye3.0的時候,卻發現auto_link有bug,一旦帖子當中的URL後面緊跟中文的話, auto_link就會把URL後面所有的中文當做URL的一部分進行格式化,直到碰到空格為止,例如:

引用

http://www.javaeye.com網站很不錯

就會被格式化為:

引用

<a href="http://www.javaeye.com網站很不錯">http://www.javaeye.com網站很不錯 </a>

看來得到rails的源代碼裡找答案了。

打開netbeans,敲快捷鍵Ctrl+O,在彈出窗口輸入:texthelper,回車,netbeans已經幫我打開了 text_helper.rb源代碼,通過Navigator窗口,很方便的定位到auto_link方法,仔細看一下,原來主要是 這個正則表達式在起作用:

Ruby代碼

AUTO_LINK_RE = %r{ 
        (             # leading text 
         <\w+.*?>|        # leading HTML tag, or 
         [^=!:'"/]|        # leading punctuation, or 
         ^            # beginning of line 
        ) 
        ( 
         (?:https?://)|      # protocol spec, or 
         (?:www\.)        # www.* 
        ) 
        ( 
         [-\w]+          # subdomain or domain 
         (?:\.[-\w]+)*      # remaining subdomains or domain 
         (?::\d+)?        # port 
         (?:/(?:(?:[~\w\+%-]|(?:[,.;:][^\s$]))+)?)* # path 
         (?:\?[\w\+%&=.;-]+)?   # query string 
         (?:\#[\w\-]*)?      # trailing anchor 
        ) 
        ([[:punct:]]|\s|<|$)    # trailing text 
        }x unless const_defined?(:AUTO_LINK_RE)

但這個正則表達式上看下看,左看右看都沒有啥問題阿。於是把這個正則表達式拷貝出來,放在一個 ruby文件裡面test.rb,一點點單獨調試,但怎麼調試都正常,即使把上面那個URL放進去,也可以正常截 斷中文。

難道是因為rails做了手腳?為了驗證這一點,在test.rb前面加上如下內容:

Ruby代碼

ENV["RAILS_ENV"] = "development" 
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")

再運行test.rb,果然!中文又被包括進去了,看來就是rails做了手腳。

再回過頭仔細看這個正則表達式,只有[\w]和字符串處理有關系,為了驗證這一點,我們做如下試驗 :

創建一個char.rb文件,內容如下:

Ruby代碼

def name 
 return "范凱" 
end

請注意!該文件保存格式請必須使用UTF-8!!

然後打開irb,進行如下交互:

引用

irb(main):001:0> load "char.rb" 
=> true 
irb(main):002:0> name 
=> "\350\214\203\345\207\257" 
irb(main):003:0> name.match /[A-Za-z0-9_]+/ 
=> nil 
irb(main):004:0> name.match /\w+/ 
=> nil

請注意標記為紅色的行,在ruby的內存中,中文字符串的編碼使用的是unicode格式,中文字符串不能 夠匹配到/[\w]+/上面去,而/[A-Za-z0-9_]+/與/\w+/是同義詞。

好了,現在啟動rails的環境:

引用

$ ./script/console 
Loading development environment. 
>> load "char.rb" 
=> [] 
>> name 
=> "鑼冨嚡" 
>> name.match /[A-Za-z0-9_]+/ 
=> nil 
>> name.match /\w+/ 
=> #

哈哈,水落石出了!!由於rails的ActiveSupport的引入,在ruby的內存當中,字符串被轉換為UTF-8 格式了(顯示亂碼是因為我的Windows操作系統是GBK編碼),而中文字符串居然可以匹配/\w+/了!

我們可以看到,由於rails在內存當中以UTF-8格式操作中文字符串,而不是ruby默認的unicode格式, 這就導致了正則表達式的歧義:/[A-Za-z0-9_]+/不能匹配中文,但是/\w+/可以匹配中文,但實際上在 ruby當中,這兩個正則表達式本應該是同義詞。

明白了問題的根源,就清楚了如何去解決auto_link的bug,修改正則表達式和相關方法,將\w替換為 A-Za-z0-9,並將其放入你的rails項目的application_helper.rb當中,這樣就可以在項目啟動以後覆蓋 rails系統類庫的定義:

Ruby代碼

 AUTO_LINK_RE = %r{ 
            (             # leading text 
             <\w+.*?>|        # leading HTML tag, or 
             [^=!:'"/]|        # leading punctuation, or 
             ^            # beginning of line 
            ) 
            ( 
             (?:https?://)|      # protocol spec, or 
             (?:www\.)        # www.* 
            ) 
            ( 
             [-0-9A-Za-z_]+      # subdomain or domain 
             (?:\.[-0-9A-Za-z_]+)*  # remaining subdomains or domain 
             (?::\d+)?        # port 
             (?:/(?:(?:[~0-9A-Za-z_\+%-]|(?:[,.;:][^\s$]))+)?)* # path 
             (?:\?[0-9A-Za-z_\+%&=.;-]+)?   # query string 
             (?:\#[0-9A-Za-z_\-]*)?  # trailing anchor 
            ) 
 }x unless const_defined?(:AUTO_LINK_RE) 
  
 def auto_link_urls(text, href_options = {}) 
  extra_options = tag_options(href_options.stringify_keys) || "" 
  text.gsub(AUTO_LINK_RE) do 
   all, a, b, c = $&, $1, $2, $3 
   if a =~ /<a\s/i # don't replace URL's that are already linked 
    all 
   else 
    text = b + c 
    text = yield(text) if block_given? 
    %(#{a}<a href="#{b=="www."?"http://www.":b}#{c}"#{extra_options}>#{text}

</a>) 
   end 
  end 
 end

OK,搞定了,這下auto_link可以正確截斷中文了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved