正则表达式匹配所有韩文(韩文)字符和音节块

时间:2018-01-03 09:40:06

标签: python regex validation character alphabet

我正在尝试验证用户输入(在Python中)并查看是否使用了正确的语言,在这种情况下使用韩语。让我们将韩语单词用于电子邮件地址:이메일주소

我可以像这样检查每个角色:

import unicodedata as ud
for chr in u'이메일 주소':
    if 'HANGUL' in ud.name(chr): print "Yep, that's a Korean character."

但这似乎非常低效,特别是对于较长的文本。当然,我可以创建一个包含所有韩语音节块的静态字典,但是该字典将包含大约25,000个字符,并且再次检查是不合理的。另外,我还需要日语和中文的解决方案,可能包含更多字符。

因此,我想使用覆盖汉语音节块的所有Unicode字符的正则表达式模式。但是我不知道是否有一个范围或者在哪里找到它。

例如,此正则表达式模式涵盖所有基于拉丁语的字符,包括括号和其他常用符号:

import re
LATIN_CHARACTERS = re.compile(ur'[\x00-\x7F\x80-\xFF\u0100-\u017F\u0180-\u024F\u1E00-\u1EFF]')

有人可以翻译这个正则表达式以匹配韩语Hangul音节块吗?或者你可以给我看一张桌子或参考来自己查找这些范围吗?

匹配中文和日文的模式也非常有用。或者一个正则表达式同时匹配所有CJK字符。我不需要区分日语和韩语。

这是一个用于该任务的Python库,但它适用于非常庞大的词典:https://github.com/EliFinkelshteyn/alphabet-detector 我无法想象对大型文本和大量用户输入有效。

谢谢!

2 个答案:

答案 0 :(得分:3)

您知道如何将Unicode分解为块,以及每个块如何表示连续的代码点范围? IE,有一个比正则表达式更有效的解决方案。

Hangul Jamo只有一个代码块,其中包含CJK blockcompatability blockHangul syllables等其他字符。

最有效的方法是使用if/then语句检查每个字符是否在可接受的范围内。你几乎可以肯定使用C扩展来提高速度。

例如,如果我只是检查Hangul块(不足,但只是一个简单的起始位置),我会使用以下代码检查字符串中的每个字符:

def is_hangul_character(char):
    '''Check if character is in the Hangul Jamo block'''

    value = ord(char)
    return value >= 4352 and value <= 4607


def is_hangul(string):
    '''Check if all characters are in the Hangul Jamo block'''

    return all(is_hangul_character(i) for i in string)

对于包含Hangul字符的大约8个blocks,可以很容易地扩展它。没有表查找,没有正则表达式编译。只是基于Unicode字符块的快速范围检查。

在C中,这也很容易(如果你希望显着的性能提升,匹配一个完全优化的库,几乎没有工作):

// Return 0 if a character is in Hangul Jamo block, -1 otherwise
int is_hangul_character(char c)
{
    if (c >= 4352 && c <= 4607) {
        return 0;
    }
    return -1;
}


// Return 0 if all characters are in Hangul Jamo block, -1 otherwise
int is_hangul(const char* string, size_t length)
{
    size_t i;
    for (i = 0; i < length; ++i) {
        if (is_hangul_character(string[i]) < 0) {
            return -1;
        }
    }
    return 0;
}

编辑粗略地看一眼CPython实现,可以看出CPython对unicodedata模块使用了这种精确的方法。 IE,尽管相对容易自己实现它,但效率很高。它仍然值得实现,因为您不必分配任何中间字符串,或使用多余的字符串比较(这可能是unicodedata模块的主要成本)。

答案 1 :(得分:0)

如果您想要一个不依赖于实用程序的 unicode-compliance 的解决方案,对于 AC00-D7AF 的主块,您可以使用

(([\352][\260-\277]|[\353\354][\200-\277]|
[\355][\200-\235])[\200-\277]|[\355][\236][\200-\243]) # mawk/gawk -b 

展开的平板是

(\355\236(\200|\201|\202|\203|\204|\205|\206|\207|
\210|\211|\212|\213|\214|\215|\216|\217|\220|\221|
\222|\223|\224|\225|\226|\227|\230|\231|\232|\233|
\234|\235|\236|\237|\240|\241|\242|\243)|
(\352(\260|\261|\262|\263|\264|\265|\266|
\267|\270|\271|\272|\273|\274|\275|\276|\277)|
\355(\200|\201|\202|\203|\204|\205|\206|\207|
\210|\211|\212|\213|\214|\215|\216|\217|\220|
\221|\222|\223|\224|\225|\226|\227|\230|\231|
\232|\233|\234|\235)|(\353|\354)
(\200|\201|\202|\203|\204|\205|\206|\207|\210|
\211|\212|\213|\214|\215|\216|\217|\220|\221|
\222|\223|\224|\225|\226|\227|\230|\231|\232|
\233|\234|\235|\236|\237|\240|\241|\242|\243|
\244|\245|\246|\247|\250|\251|\252|\253|\254|
\255|\256|\257|\260|\261|\262|\263|\264|\265|
\266|\267|\270|\271|\272|\273|\274|\275|\276|
\277))(\200|\201|\202|\203|\204|\205|\206|\207|\210
|\211|\212|\213|\214|\215|\216|\217|\220|\221
|\222|\223|\224|\225|\226|\227|\230|\231|\232
|\233|\234|\235|\236|\237|\240|\241|\242|\243
|\244|\245|\246|\247|\250|\251|\252|\253|\254
|\255|\256|\257|\260|\261|\262|\263|\264|\265
|\266|\267|\270|\271|\272|\273|\274|\275|\276|\277))

如果你需要额外的东西 - jamo、兼容性 jamo、圆圈形式、括号形式和半角形式,把这个附加到上面的那个

要么

 [\341\204\200-\341\207\277
  \343\204\260-\343\206\217
  \352\245\240-\352\245\277
  \355\236\260-\355\237\277
  \343\200\256-\343\200\257
  \343\210\200-\343\210\236
  \343\211\240-\343\211\276
  \357\276\240-\357\276\276
  \357\277\202-\357\277\207
  \357\277\212-\357\277\217
  \357\277\222-\357\277\227
  \357\277\232-\357\277\234]  # gawk unicode-mode only

 ((\343\205|\355\237|\341(\204|\205|\206|\207))
(\200|\201|\202|\203|\204|\205|\206|\207|\210|\211
|\212|\213|\214|\215|\216|\217|\220|\221|\222|\223
|\224|\225|\226|\227|\230|\231|\232|\233|\234|\235
|\236|\237|\240|\241|\242|\243|\244|\245|\246|\247
|\250|\251|\252|\253|\254|\255|\256|\257|\260|\261
|\262|\263|\264|\265|\266|\267|\270|\271|\272|\273
|\274|\275|\276|\277)|(\343\204|\355\236)(\260|\261
|\262|\263|\264|\265|\266|\267|\270|\271
|\272|\273|\274|\275|\276|\277)|\343\206(\200|\201
|\202|\203|\204|\205|\206|\207|\210|\211|\212|\213
|\214|\215|\216|\217)|\352\245(\240|\241|\242|\243
|\244|\245|\246|\247|\250|\251|\252|\253|\254|\255
|\256|\257|\260|\261|\262|\263|\264|\265|\266|\267
|\270|\271|\272|\273|\274|\275|\276|\277)
|\343\200\256|\343\200\257|
\343\210(\200|\201|\202|\203|\204|\205|\206|\207
|\210|\211|\212|\213|\214|\215|\216|\217|\220|\221|
\222|\223|\224|\225|\226|\227|\230|\231|\232|\233|
\234|\235|\236)|(\343\211|\357\276)
(\240|\241|\242|\243|\244|\245|\246|\247|\250|\251
|\252|\253|\254|\255|\256|\257|\260|\261|\262|\263
|\264|\265|\266|\267|\270|\271|\272|\273|\274|\275
|\276)|\357\277(\202|\203|\204|\205|\206|\207|\212
|\213|\214|\215|\216|\217|\222|\223|\224|\225|\226
|\227|\232|\233|\234))

如果您只需要构成 11,172 个音节集合的现代 jamo,那么它就干净多了:

((\341)((\204)[\200-\222]|(\205)[\241-\265]|(\206)[\250-\277]|(\207)[\200-\202]))

或者如果你更喜欢没有多余的括号:

(\341(\204[\200-\222]|\205[\241-\265]|\206[\250-\277]|\207[\200-\202]))

ps :我只是为了可读性而在这里格式化。这些八进制代码之间没有任何空格制表符或换行符。它是一个连续的字符串。

就我个人而言,我更愿意自己使用干净的现代正则表达式,但使用这些八进制对我自己来说是必要的邪恶,以使 mawk1.3.4 和 mawk2-beta 完全符合 UTF8。

(至少在 lengthC() ordC() substrC() 和字符级拆分方面,但在 UC13 代码点级别,加上仅韩文 NFD 到 NFC。

但没有像字素簇或双向文本那样花哨的东西)