首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JavaEye 3.0 開發手記之二:Rails UTF-8 環境下正則表達式 \w 匹配中文 Bug 修復

     編輯:Java 相關知識

Rails `auto_link` 輔助方法在 UTF-8 環境下將 URL 後緊跟的中文誤判為 URL 一部分,根因是 ActiveSupport 修改了 Ruby 字符串編碼行為,導致正則 `\w` 與 `[A-Za-z0-9_]` 行為不一致。本文記錄排查過程與修復方案。

現象重現

輸入: "https://www.javaeye.com網站很不錯"
預期: <a href="https://www.javaeye.com">https://www.javaeye.com</a>網站很不錯
實際: <a href="https://www.javaeye.com網站很不錯">https://www.javaeye.com網站很不錯</a>

源碼定位

NetBeans Ctrl+O 打開 `text_helper.rb`,核心正則 `AUTO_LINK_RE` 中使用 `\w` 匹配域名/路徑字符。

關鍵發現:Rails 改變了 \w 語義

純 Ruby 環境(Unicode 內部編碼):

irb> name = "范凱"
irb> name.match /\w+/  # => nil
irb> name.match /[A-Za-z0-9_]+/  # => nil

載入 Rails 環境(`script/console`,UTF-8 內部編碼):

>> name = "范凱"
>> name.match /\w+/  # => #<MatchData "范凱">  匹配上了!
>> name.match /[A-Za-z0-9_]+/  # => nil

結論:ActiveSupport 將字符串按 UTF-8 操作,導致 `\w` 能匹配中文字符,而字符類 `[A-Za-z0-9_]` 仍僅匹配 ASCII。兩者在 Ruby 標準語義下本應等價, Rails 打破了這一約定。

修復方案:覆寫正則與輔助方法

在 `application_helper.rb` 中重新定義 `AUTO_LINK_RE` 和 `auto_link_urls`,將所有 `\w` 替換為显式字符類 `0-9A-Za-z_`:

AUTO_LINK_RE = %r{
  ( <\w+.*?> | [^=!:'"/] | ^ )
  ( (?:https?://) | (?:www\.) )
  ( [-0-9A-Za-z_]+ (?:\.[-0-9A-Za-z_]+)* (?::\d+)? 
    (?:/(?:(?:[~0-9A-Za-z_\+%-]|(?:[,.;:][^\s$]))+)?)* 
    (?:\?[0-9A-Za-z_\+%&=.;-]+)? (?:\#[0-9A-Za-z_\-]*)? )
} x unless const_defined?(:AUTO_LINK_RE)

def auto_link_urls(text, href_options = {})
  # ... 同源碼邏輯,使用修正後的 AUTO_LINK_RE ...
end

專案啟動時自動覆蓋 Rails 內建定義,`auto_link` 恢復正確截斷中文行為。

深層教訓

框架層修改核心類語義(String/Regexp 行為)極具隱蔽破壞力。遇到正則異常優先檢查 `$KCODE`、`ActiveSupport::Multibyte` 等全局修改。显式字符類比 `\w` 等簡寫更安全、可移植。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved