PAYATHON 2026

Rails 中如何过滤 Unicode 搜索字符并保留越南语?

数据小陈

结论

不要按“字符码值高于某个阈值就删除”的规则处理。不同语言的 Unicode 字母分布在多个区段,越南语的声调字符也可能由组合符号表示。按数值截断会误删有效文字。

在 Rails 端,可以保留 Unicode 字母、组合标记和空白,并单独移除数学字母数字符号区段 U+1D400 到 U+1D7FF。𝓵𝓲𝓵𝓵𝔂𝓬𝓻𝓸𝓯𝓽 中的字符就在这个区段。过滤后,如果搜索词为空,就跳过 MATCH 查询。

Ruby 过滤示例

def sanitize_search_term(value)
  value.to_s
       .gsub(/[\u{1D400}-\u{1D7FF}]/u, "")
       .gsub(/[^\p{L}\p{M}\s]/u, " ")
       .gsub(/\s+/, " ")
       .strip
end

这里的 \p{L} 用来保留 Unicode 字母,\p{M} 保留组合标记,后者对某些分解形式的重音字符有用。第二次替换会把其余字符(包括布尔全文搜索运算符 +)换成空格。代码不会把数学字母转换成普通拉丁字母;这个示例会直接删除它们。

使用结果前,先检查搜索词是否为空:

term = sanitize_search_term(params[:q])

if term.present?
  # 在这里构造 BOOLEAN MODE 查询并执行搜索
else
  # 不执行 MATCH 查询,按应用需要返回空结果
end

如果搜索逻辑会给词项添加 +,应先过滤并确认词项非空,再构造布尔查询。将构造好的查询字符串作为 SQL bind 参数传入 AGAINST (?),不要直接插入 SQL 文本。参数绑定可以避免把输入当作 SQL 语法,但 BOOLEAN MODE 仍会解析参数内容,所以过滤和空值检查仍有必要。

越南语与边界

上述规则会保留 trường đại học 中的越南语字母和声调标记。不过,搜索能否按预期匹配,还取决于 MySQL 的字符集、排序规则、全文索引解析器和索引配置。现有日志不足以确认这些配置,因此应使用与生产环境相同的配置验证目标词的搜索结果。

这套规则只针对日志中的数学字母数字符号,不是完整的 Unicode 反混淆方案。Unicode 没有通用的数值分界,能可靠地区分所有语言中的“普通字母”和装饰性字形。如果还要处理其他相似字符,应根据具体输入补充明确的区段或策略。也不要用 NFKC 解决这个问题:它可能把装饰字形转换成普通字母,而这里需要丢弃这类输入。

备注:内容仅供参考。