regex 使用正则表达式匹配UTF-8编码的任意汉字

i2byvkas  于 2023-04-13  发布在  其他
关注(0)|答案(8)|浏览(259)

例如,我想匹配一个由mn中文字符组成的字符串,那么我可以用途:

[single Chinese character regular expression]{m,n}

是否存在单个汉字的正则表达式,它可以是任何存在的汉字?

epggiuax

epggiuax1#

匹配一个中文(CJK)字符的正则表达式是

\p{script=Han}

可以简单地认为

\p{Han}

这里假设你的正则表达式编译器满足RL1.2UTS#18中的属性**Unicode正则表达式 * 的要求。Perl和Java 7都满足这个规范,但其他很多都不满足。

hi3rlvi2

hi3rlvi22#

在Java中

\p{InCJK_UNIFIED_IDEOGRAPHS}{1,3}
w80xi6nr

w80xi6nr3#

在C#中

new Regex(@"\p{IsCJKUnifiedIdeographs}")

这是在微软文档中
以下是来自Wikipedia的更多信息:CJK Unified Ideographs
基本块命名为中日韩统一表意文字(4 E00 - 9 FFF)包含U+4 E00到U+9 FEF范围内的20,976个基本汉字。该块不仅包括中文书写系统中使用的字符,还包括日语书写系统中使用的汉字和在韩国使用的汉字,后者在韩国的使用正在减少。该块中的许多字符在所有三种书写系统中使用。而其他的则只在三种文字中的一种或两种中使用。越南的Nôm文字也使用汉字(现已过时)。

l0oc07j2

l0oc07j24#

是否存在单个汉字的正则表达式,它可以是任何存在的汉字?

推荐

要使用Flex兼容的词法分析器将模式与中文字符和其他Unicode代码点匹配,可以使用与Flex向后兼容的RE/flex lexical analyzer for C++。RE/flex支持Unicode,并与野牛一起构建词法分析器和解析器。
您可以在RE/flex规范中编写Unicode模式(和UTF-8正则表达式),例如:

%option flex unicode
%%
[肖晗]   { printf ("xiaohan/2\n"); }
%%

使用全局%option unicode来启用Unicode。您还可以使用局部修饰符(?u:)将Unicode限制为单个模式(因此其他内容仍然是ASCII/8位,如Flex中所示):

%option flex
%%
(?u:[肖晗])   { printf ("xiaohan/2\n"); }
(?u:\p{Han})  { printf ("Han character %s\n", yytext); }
.             { printf ("8-bit character %d\n", yytext[0]); }
%%

选项flex启用Flex兼容性,因此您可以使用yytextyylengECHO等。如果没有flex选项,RE/flex将接受Lexer方法调用:text()(对于std::stringstd::wstring,或者str()wstr())、size()(对于宽字符长度,或者wsize())和echo()。RE/flex方法调用是更干净的IMHO,并且包括宽字符操作。

背景

在普通的老Flex中,我最终定义了丑陋的UTF-8模式来捕获ASCII字母和UTF-8编码的字母,用于需要支持Unicode标识符id的编译器项目:

digit           [0-9]
alpha           ([a-zA-Z_\xA8\xAA\xAD\xAF\xB2\xB5\xB7\xB8\xB9\xBA\xBC\xBD\xBE]|[\xC0-\xFF][\x80-\xBF]*|\\u([0-9a-fA-F]{4}))
id              ({alpha})({alpha}|{digit})*

alpha模式支持在标识符中使用的ASCII字母、下划线和Unicode代码点(\p{L}等)。该模式允许比绝对必要的更多的Unicode码点,以保持该模式的大小可管理,因此,它以紧凑性换取了一些不准确性,并允许UTF-8超长字符在某些情况下不是有效的UTF-8。如果您正在考虑这种方法,请注意问题和安全问题。请使用支持Unicode的扫描仪生成器,例如RE/flex

安全性

在Flex模式中直接使用UTF-8时,有几个问题:
1.在Flex中编码您自己的UTF-8模式以匹配任何Unicode字符可能容易出错。模式应仅限于有效Unicode范围内的字符。Unicode代码点涵盖范围U+0000到U+ D 7 FF和U+E000到U+10 FFFF。范围U+D800到U+DFFF是为UTF-16代理对保留的,并且是无效代码点。使用工具将Unicode范围转换为UTF-8时,请确保排除无效的代码点。
1.模式应该拒绝过长的和其他无效的字节序列。无效的UTF-8不应该被默认接受。
1.要在lexer中捕获词法输入错误,需要一个特殊的.(dot)匹配有效和无效的Unicode,包括UTF-8溢出和无效的字节序列,以便产生输入被拒绝的错误消息。如果您使用dot作为“catch-all-else”来产生错误消息,但您的dot不匹配无效的Unicode,那么你的lexer将挂起(“scanner is camming”)或者你的lexer将在Flex的“default rule”输出中显示垃圾字符。
1.您的扫描仪应识别输入中的UTF BOM(Unicode字节顺序标记),以切换到UTF-8、UTF-16(LE或BE)或UTF-32(LE或BE)。
1.正如您所指出的,像[unicode characters]这样的模式在Flex中根本不起作用,因为方括号列表中的UTF-8字符是多字节字符,每个单字节字符都可以匹配,但不能匹配UTF-8字符。
另请参阅RE/flex用户指南中的无效UTF编码。

e0uiprwp

e0uiprwp5#

对于大多数编程语言,匹配99.9%以上中文字符的正则表达式为:

\u4E00-\u9FFF

  • 适用于:Python、现代Javascript、Golang、Rust但不包括PHP。*

如果你的语言在其他答案中不支持像{Han}/{script=Han}/{IsCJKUnifiedIdeographs}这样的符号,这很有用。
注:这对应于CJK Unified Ideographs,并包括其他语言,如韩语,日语和越南语。

blpfk2vs

blpfk2vs6#

在Java 7和更高版本中,格式应该是:“\p{IsHan}”

gstyhher

gstyhher7#

刚刚解决了一个类似的问题
当你有太多的东西要匹配时,最好使用negated-set并声明你不想匹配的东西:
所有但不是数字:^[^0-9]*$
第二个^将实现否定

u4dcyp6a

u4dcyp6a8#

就像这样

package main

import (
    "fmt"
    "regexp"
)

func main() {
    compile, err := regexp.Compile("\\p{Han}") // match one any Chinese character
    if err != nil {
        return
    }
    str := compile.FindString("hello 世界")
    fmt.Println(str) // output: 世
}

相关问题