- mysql/oracle 正则匹配中文
编码知识
- GBK (GB2312/GB18030)
\x00-\xff GBK双字节编码范围
\x20-\x7f ASCII
\xa1-\xff 中文
\x80-\xff 中文 - UTF-8 (Unicode)
\x4e00-\x9fa5 (中文,含有繁体) \x4e00-\x9fff (包括其他繁体) \xf900-\xfa2d (输入法打不出来的汉字)
\x3130-\x318F (韩文)
\xac00-\xd7a3 (韩文)
\x0800-\x4e00 (日文)
\x2e80-\x9fff (中日韩文)
- 补充知识:
2e80~33ffh:中日韩符号区。收容康熙字典部首、中日韩辅助部首、注音符号、日本假名、韩文音符,中日韩的符号、标点、带圈或带括符文数字、月份,以及日本的假名组合、单位、年号、月份、日期、时间等。
3400~4dffh:中日韩认同表意文字扩充a区,总计收容6,582个中日韩汉字。
4e00~9fffh:中日韩认同表意文字区,总计收容20,902个中日韩汉字。
a000~a4ffh:彝族文字区,收容中国南方彝族文字和字根。
ac00~d7ffh:韩文拼音组合字区,收容以韩文音符拼成的文字。
f900~faffh:中日韩兼容表意文字区,总计收容302个中日韩汉字。
fb00~fffdh:文字表现形式区,收容组合拉丁文字、希伯来文、阿拉伯文、中日韩直式标点、小符号、半角符号、全角符号等。
总结正则:[\x{2000}-\x{9fff}\x{ff00}-\x{ffef}\x09\x0a\x0d\x20-\x7e]
// UTF-8 编码字符理论上可以最多到 6个字节长(最小1个字节),但目前全世界的所
// 有文字和符号种类加起来也只要编到 4个字节长就够了。
// UTF-8 是以 8位(即 1个字节)为单元对原始码进行编码(注意一
// 点:这里所讲的原始码都是指Unicode码),并规定:多字节码(2个字
// 节以上才称为多字节)以转换后第1个字节起头的连续“1”的数目(这
// 些连续“1”称为标记位),表示转换成几个字节:“110”连续两个
// “1”,表示转换结果为2个字节,“1110”表示3个字节,而“11110”
// 则表示4个字节……跟随在标记位之后的“0”,其作用是分隔标记位和
// 字符码位。第2~第4个字节的起头两个位固定设置为“10”,也作为标
// 记,剩下的6个位才做为字符码位使用。
// 原始码(16进制) UTF-8编码(二进制)
// --------------------------------------------
// 0000 - 007F 0xxxxxxx
// 0080 - 07FF 110xxxxx 10xxxxxx
// 0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
// ……
// --------------------------------------------
C/C++中的wchar不支持UTF8,但支持unicode(2个字节长度)
使用char存储UTF8字符后指定codepage,可将字符转换为其他编码
占用3个字节的范围
U+2E80 - U+2EF3 : 0xE2 0xBA 0x80 - 0xE2 0xBB 0xB3 共 115 个
U+2F00 - U+2FD5 : 0xE2 0xBC 0x80 - 0xE2 0xBF 0x95 共 213 个
U+3005 - U+3029 : 0xE3 0x80 0x85 - 0xE3 0x80 0xA9 共 36 个
U+3038 - U+4DB5 : 0xE3 0x80 0xB8 - 0xE4 0xB6 0xB5 共 7549 个
U+4E00 - U+FA6A : 0xE4 0xB8 0x80 - 0xEF 0xA9 0xAA 共 44138 个
U+FA70 - U+FAD9 : 0xEF 0xA9 0xB0 - 0xEF 0xAB 0x99 共 105 个
合计: 52156 个
占用4个字节的范围
U+20000 - U+2FA1D : 0xF0 0xA0 0x80 0x80 - 0xF0 0xAF 0xA8 0x9D 共 64029 个
合计: 64029 个
后来说需要查询日文 参考资料得知:
utf-8 (unicode)
/u4e00-/u9fa5 (中文)
/x3130-/x318f (韩文)
/xac00-/xd7a3 (朝鲜文)
/u0800-/u4e00 (日文)
汉字正则: e[4-9][0-9a-f]{4}
含中文: where hex(name) regexp ‘e[4-9][0-9a-f]{4}’
我表示很纳闷,这个正则如何而来的。
sql中执行:
select *,hex(name) from test;
‘1’, ‘我是中国人’, ‘E68891E698AFE4B8ADE59BBDE4BABA’
得知: 我-E68891,是-E698A,中-E4B8AD,国-E59BBD,人-E4BABA
也不知道啥么东西,用chrome “FE web前端助手"字符串编码转换后的知是utf8, 我->我
接着就想到在python中获取他的utf8编码:
u’我’
u’\u6211’
‘我’
‘\xe6\x88\x91’
“我”在sql中对应的HEX 16进制结果就是E68891,正好符合。
上文所提到的正则 ‘e[4-9][0-9a-f]{4}’也就有解了。
u’\u4e00’.encode(‘utf8’)
‘\xe4\xb8\x80’
u’\u9fa5’.encode(‘utf8’)
‘\xe9\xbe\xa5’
诈一看,还真是这样,但是b880-bea5区间仅仅用0-f笼统该快太不规范了…不做处理了.
中文utf8编码区间:\u4e00-\u9fa5 --> e4b880-e9bea5 --> e[4-9][0-9a-f]{4}
日文utf8编码区间:\u0800-\u4e00 --> e4b880 e9bea5
e[0-4][0-9a-b][0-8][0-8]0
e[0-4][0-9a-a][0-9a-f]{3}
e[0-4][0-9a-b][0-8][0-7][0-9a-f]
日文正则:e[0-4][0-9a-a][0-9a-f]{3}|e[0-4][0-9a-b][0-8][0-7][0-9a-f]|e[0-4][0-9a-b][0-8][0-8]0|e[0-4][0-9a-b][0-8][0-7][0-9a-f]
日文正则(简化):e[0-4][0-9a-a][0-9a-f]{3}|e[0-4][0-9a-b][0-8][0-7][0-9a-f]
韩文utf8编码区间:\xac00-\xd7a3 --> c2ac00 c397a3
正则:
c[2-2][0-9]6[0-9a-f]{2}
c[2-2][0-9]6[0-9][0-9a-f]
c[2-2][0-9]6[0-9]a[0-3]
c[2-2]a[0-9a-b][0-9a-f]{2}
c[2-2][0-9a-a][0-9a-c]00
…
突然发现:韩文正则将会很多很复杂…
那干脆用十进制吧…
select conv(‘c2ac00’,16,10),conv(‘c397a3’,16,10);
12758016, 12818339
貌似需要数值的还要用正则,太麻烦了,用到for循环还不如直接用十六进制between and
————————————————
版权声明:本文为CSDN博主「zhipeng-python」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012731379/article/details/64125572
选取中文:
mysql 5.7写法:
select * from test1 where hex(name) regexp ‘e[4-9][0-9a-f]{4}’;
mysql 8 写法:
select * from test1 where name REGEXP ‘[\x{4e00}-\x{9fa5}]’;
\x表示十六进制
4e00-9fa5表示汉字的十六进制unicode编码
chatgpt回答: 回答错误,要加\x转义字符
在 MySQL 中,您可以使用 REGEXP 或 RLIKE 运算符配合正则表达式来实现这个目的。
以下是一个示例查询,用于判断字段 column_name 是否包含中文字符:
SELECT *
FROM table_name
WHERE column_name REGEXP ‘[\x{4e00}-\x{9fa5}]’;
这个查询使用了正则表达式中的 Unicode 转义序列,其中 \x{4e00} 表示 Unicode 码点 4e00,即中文字符的起始码点,\x{9fa5} 表示 Unicode 码点 9fa5,即中文字符的结束码点。
如果查询结果为空,则表示该字段不包含中文字符;如果查询结果不为空,则表示该字段包含中文字符。
请注意,上述查询中的 column_name 和 table_name 需要根据实际情况进行替换。
5.7版本上述报错
select * from test1 where name REGEXP ‘[\x{4e00}-\x{9fa5}]’ Error Code: 1139. Got error ‘invalid character range’ from regexp 0.000 sec
这个错误信息表明在执行正则表达式时遇到了一个无效的字符范围。具体来说,错误代码1139表示在正则表达式中存在一个无效的字符范围。
问题出在正则表达式 [\x{4e00}-\x{9fa5}] 上。这个正则表达式试图匹配任何在Unicode码点4e00到9fa5之间的字符,这个范围包括了大部分的中文字符。
问题可能出在MySQL的版本上。在某些旧版本的MySQL中,可能不支持使用\x{…}这种形式的Unicode转义序列。
解决方案:
升级MySQL版本:确保你使用的是支持这种Unicode转义序列的MySQL版本。新版本的MySQL通常支持这种转义序列。
使用其他方式表示范围:如果你不能升级MySQL版本,你可以尝试使用其他方式来表示中文字符的范围。例如,你可以使用两个单独的正则表达式来匹配单个字符:
sqlSELECT * FROM test1 WHERE
name REGEXP ‘[\x{4e00}-\x{9fa4}]’
OR
name REGEXP ‘[\x{9fa5}-\x{ffff}]’;
这个查询尝试匹配码点4e00到9fa4之间的字符,或者码点9fa5到ffff之间的字符。这样做的效果是一样的,但绕过了对Unicode转义序列的限制。
3. 检查数据:确保你的数据中确实包含中文字符,并且确保它们存储在正确的字符集和校对序列中(例如,使用utf8mb4字符集)。
4. 使用LIKE语句:如果你只是想要检查字段中是否包含中文字符,而不是进行精确匹配,你可以考虑使用LIKE语句结合通配符来检查:
sqlSELECT * FROM test1 WHERE name LIKE ‘%[一-龥]%’;
这个查询将返回所有包含中文字符的记录。注意,这个查询可能不如正则表达式精确,但它通常对于简单的匹配任务来说是足够的。
在计算机编程和数据传输中,"\x" 是一个前缀,用来表示一个字符的十六进制(hexadecimal)表示。在某些编程语言(如 Python)中,当一个字符前有 “\x” 前缀时,该字符会被解释为对应的十六进制值。
例如,在 Python 中:
pythonprint("\x48") # 这将打印字符 ‘H’,因为十六进制值 48 对应于 ASCII 码中的 ‘H’
注意:在不同的编程语言和环境中,对 “\x” 的处理可能会有所不同。
计算机编程中,"\u" 是一个前缀,用来表示一个字符的 Unicode 码点。Unicode 是一个字符编码标准,用于统一不同语言的字符编码。
在 Python 中,使用 “\u” 前缀可以表示一个 Unicode 码点,并用于生成相应的字符。例如:
pythonprint("\u4e00") # 这将打印中文字符 ‘一’,因为 Unicode 码点 4e00 对应于中文字符 ‘一’
注意:在不同的编程语言和环境中,对 “\u” 的处理可能会有所不同。在使用前最好查阅相关语言的文档以了解具体的语法和用法。
mysql 中文匹配
最近一个情感分析项目,由于采集到的评论数据中有不含中文的字符串,导致情感分析模型的准确度不高,需要过滤掉不包含中文的字符串。以下是BI报表上显示的分析结果。
查看后台数据库中的数据,如下图,绿色部分不包含中文字符的字段,是我们需要过滤掉。
在参考资料的2篇博客中,找到了对应的解决办法,用mysql里的HEX函数可以把字段转为16进制,然后正则匹配 对应中文的code码。
我们的字段存储的是utf8,所以查询了utf8汉字编码对照表 (如果你的是gbk系的就查对应的编码对照就可以了)
如下图,可以总结出utf8汉字编码16进制的正则匹配格式是: e[4-9][0-9a-f]{4}
以下是正则匹配包含中文的示例,
以下是正则匹配非中文字符的示例,
Oracle 匹配中文
oracle正则表达式regexp_substr、regexp_like、regexp_replace是无法像其他正则表达式一样用[\u4e00-\u9fa5]来匹配中文的。
所以,我们需要用另一种方式来实现oracle正则表达式匹配中文。
我们需要用到oracle的内置函数UNISTR(str):
ASCIISTR语法:asciistr(str) 功能:返回字符串的规则表现形式,英文和数字变为规则的,中文则前面有‟\‟符号,返回unicode编码形式。
UNISTR(str)函数是相反的过程,将unicode编码变为字符。
用法:
select regexp_like(‘中文测试’,’[’ || unistr(’\4e00’) || ‘-’ || unistr(’\9fa5’) || ‘]’) from dual;
with chenxu as
(
select ‘老头子大帅哥!handsome!イケメン!’ as a from dual
)
select a,regexp_replace(a,’[^’ || unistr(’\4E00’) || ‘-’ || unistr(’\9FA5’) || ‘]’,’’)
from chenxu
;
在Oracle中,可以使用REGEXP_LIKE函数来判断一个字段是否包含中文字符。
以下是一个示例查询,用于判断字段"column_name"是否包含中文字符:
sqlSELECT column_name
FROM table_name
WHERE REGEXP_LIKE(column_name, ‘[\u4e00-\u9fa5]’);
这个查询使用了正则表达式来匹配中文字符的Unicode范围。如果查询结果为空,则表示该字段不包含中文字符;如果查询结果不为空,则表示该字段包含中文字符。
Oracle判断字段中是否包含中文(若有,取出该中文的方法)
一、问题说明
在处理数据的时候,需要判断某个字段字符串中是否有中文,若有则取出中文。
二、解决办法
首先如何判断某个字段字符串中是否有中文。这里介绍三种方法:
1、采用ASCIISTR函数
说明:ASCIISTR函数用于返回字符的ASCII形式的字符串;非ASCII的字符被转化为\xxxx的形式。换句话说:如果字符中包含中文,则必定会有\xxxx的字符。所以,我们直接利用ASCIISTR函数匹配’'即可判断。
2、采用length和lengthb的原理
说明:中文下length返回的是字符个数,中文占1字符,lengthb返回的是字节个数,中文占2字节,根据中文的特性即可解决。
3、使用CONVERT函数判别
说明:CONVERT(要转换的字符串,目标字符集,原字符集),CONVERT函数用于转换字符串的字符集;所以我们可以利用中文的字符集是utf-8来判断。
上面介绍了如何判断某个字段字符串中是否有中文,在成功判断字段中是否有中文之后;那么该如何取出字段中的中文呢?
这里介绍一种快速准确的办法:
函数创建成功后,直接传jldw调用就可获取该字符的中文了。
源码如下:
create or replace function getCustText(custName varchar2) return varchar2 is
Result varchar2(100); --返回的结果字符串
tmp_custName varchar2(100); --临时变量
count_str number; --字符串中字符的个数
i number:=1; --循环变量
str_ascii number; --当前等待判断字符的ascii码
current_char varchar2(10); --当前等待判断的字符
begin
select length(custName) into count_str from dual; --取出待处理字符串的长度
while i<count_str loop —根据待处理字符串长度(counts)?,逐个字符判断处理
current_char:=substr(custName,i,1);
select ASCII(current_char) into str_ascii from dual;
if str_ascii>45216 then
tmp_custName:=tmp_custName||current_char;
end if;
i:=i+1;
end loop;
Result:=tmp_custName;
return(Result);
end getCustText;




