卿少納言

卿少納言

JavaScript & Japanese, Python & Polyglot, TypeScript & Translate.
zhihu
github
email
x

如何用正則表達式匹配漢字的所有相關字符

一個看似簡單的需求,但網上流傳甚廣的[u4e00-u9fa5]其實有點問題。

如何用正則表達式匹配漢字的所有相關字符#

從維基百科上 Unicode 頁面的歷史章節給出的碼表範圍就能發現:中文互聯網流傳甚廣的[u4e00-u9fa5]應該是只計算了【CJK Unified Ideographs】內的漢字,但這部分的內容其實只占了全部漢字的五分之一。雖然 CJK Unified Ideographs 以使用頻率來分區,但如果是開發語言文字相關的專業工具的話,最好全面覆蓋所有相關字符。

範圍名稱字數
U+4E00 - U+9FFFCJK Unified Ideographs20,992
U+3400 - U+4DBFCJK Unified Ideographs Extension A6,592
U+20000 - U+2A6DFCJK Unified Ideographs Extension B42,720
U+2A700 - U+2B738CJK Unified Ideographs Extension C4,154
U+2B740 - U+2B81DCJK Unified Ideographs Extension D222
U+2B820 - U+2CEA1CJK Unified Ideographs Extension E5,762
U+2CEB0 - U+2EBE0CJK Unified Ideographs Extension F7,473
U+30000 - U+3134ACJK Unified Ideographs Extension G4,939
U+31350 - U+323AFCJK Unified Ideographs Extension H4,192
U+2EBF0 - U+2EE5FCJK Unified Ideographs Extension I622
合計97,668

如果遇到了 UniCode 相關的問題,最好的方法還是查閱 Unicode 官方提供的文檔 Unicode 15.1 Character Code Charts,文檔裡提到和漢字相關的字符除了上面的【CJK Unified Ideographs】,還有漢字相關的符號(部首、注音符號、拼音)、私有區等等。

下面給一個 Python 實現的例子:

"""匹配漢字相關字符"""
import re

# noinspection RegExpDuplicateCharacterInClass
ideographs_reg = re.compile(
    r"""(?P<cjk_unified_ideographs>[\u4E00-\u9FFF])|
        (?P<extension_a>[\u3400-\u4DBF])|
        (?P<extension_b>[\u20000-\u2A6DF])|
        (?P<extension_c>[\u2A700-\u2B738])|
        (?P<extension_d>[\u2B740-\u2B81D])|
        (?P<extension_e>[\u2B820-\u2CEA1])|
        (?P<extension_f>[\u2CEB0-\u2EBE0])|
        (?P<extension_g>[\u30000-\u23134A])|
        (?P<extension_h>[\u31350-\u323AF])|
        (?P<extension_i>[\u2EBF0-\u2EE5F])|
        (?P<compatibility_ideographs>[\uF900-\uFAFF])| # 兼容區:([\x{F900}-\x{FAD9}])
        (?P<compatibility_ideographs_supplement>[\u2F800-\u2FA1F])| # 兼容擴展區:([\x{2F800}-\x{2FA1D}])
        (?P<kangxi_radicals>[\u2F00-\u2FDF]) | # 康熙部首:([\x{2F00}-\x{2FD5}])
        (?P<radicals_supplement>[\u2E80-\u2EFF]) | # 部首擴展:([\u2E80-\u2EF3])
        (?P<cjk_strokes>[\u31c0-\u31ef]) | # 漢字筆畫:([\u31C0-\u31E3])
        (?P<ideographic_description_characters>[\u2FF0-\u2FFF]) #漢字結構:([\u2FF0-\u2FFB])
        (?P<bopomofo>[\u3100-\u312F])| # 漢語注音:([\u3105-\u312F])
        (?P<bopomofo_extend>[\u31A0-\u31BF])| # 注音擴展:([\u31A0-\u31BA])
        (?P<private_use_area>[\uE000-\uF8FF])| # 私有區:([\uE000-\uF8FF])
        (?P<supplementary_private_use_area_a>[\uF0000-\uFFFFF])| # 私用PUA-A:([\uF0000-\uFFFFF])
        (?P<supplementary_private_use_area_b>[\u100000-\u10FFFD])| # 私用PUA-B:([\u100000-\u10FFFF])
"""
)


def match_chinese_ideographs(input_text: str) -> bool:
    """匹配是否含有漢字相關字符

    Args:
        input_text (str): 需要匹配的字符串

    Returns:
        只要包含漢字相關的字符就返回 True
    """
    result = False
    for char in input_text:
        if re.search(ideographs_reg, char) is not None:
            print(re.match(ideographs_reg, char).groupdict())
            result = True
    return result

match_chinese_ideographs("食物")

補充#

感謝 amob 提供的建議:

我剛剛看到你博客寫的關於正則匹配漢字的文章,我個人對此有些經驗(無聊處理過一些生僻字特多的詞典)。目前 \p {han} 還只是基於 Unicode 13.0 的,許多新漢字都無法匹配,\p {Unified_Ideograph}/u 沒用過,估計匹配不了一些特殊情況。

經站內高人 jcz777 指點,目前最理想的匹配碼位如下:

基本區:([\x{3007}\x{4e00}-\x{9fff}])
A區:([\x{3400}-\x{4DBF}])
B區:([\x{20000}-\x{2A6DF}])
C區:([\x{2A700}-\x{2B73F}])
D區:([\x{2B740}-\x{2B81F}])
E區:([\x{2B820}-\x{2CEA1}])
F區:([\x{2CEB0}-\x{2EBE0}])
G區:([\x{30000}-\x{3134A}])
H區:([\x{31350}-\x{323AF}])
I區:([\x{2EBF0}-\x{2EE5F}])
兼容區:([\x{F900}-\x{FAD9}])
兼容擴展區:([\x{2F800}-\x{2FA1D}])
康熙部首:([\x{2F00}-\x{2FD5}])
漢字筆畫:([\x{31C0}-\x{31E3}])
漢字結構:([\x{2FF0}-\x{2FFB}])
漢語注音:([\x{3105}-\x{312F}])
注音擴展:([\x{31A0}-\x{31BA}])
部首擴展:([\x{2E80}-\x{2EF3}])
私有區:([\x{E000}-\x{F8FF}])
私用PUA-A:([\x{F0000}-\x{FFFFF}])
私用PUA-B:([\x{100000}-\x{10FFFF}])

再算上這幾個,
𝍦、𝍳、𝍳、𝍴、𝍵
〡、〢、〣、〤、〥、〦、〧、〨、〩、〸

參考#

JavaScript 正則表達式匹配漢字:[[Python]] 沒有這篇文章的提到的/\p{Unified_Ideograph}/u、和/\p{Script=Han}/u類似的方法,感覺可以寫一個第三方庫的價值(攤手

Python: 组合方式构建复杂正则:介紹了一種在實際開發場景下,如何構建易於修改和調試的正則用法。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。