oracle汉字替换星号,更加实用的识别汉字(GBK)的自定义函数

本帖最后由 atgc 于 2014-1-5 19:19 编辑

几年前写过一个识别汉字的函数

http://www.itpub.net/thread-847680-1-1.html

但是只能识别GB2312的6763个汉字,现在做了扩展,可以识别GBK的21003个汉字

包括CJK(中日韩),以及少量部首,如果不要这些部首,也可以修改函数过滤掉

新函数性能比旧函数好,把旧函数里的SELECT语句去掉了,并且做了些简单的优化,性能还有优化余地

缺点,调用比旧函数稍微麻烦一些,主要是那个DUMP函数只能在select语句中执行

参考资料

http://baike.baidu.com/link?url=rPKTqUcCknukF72Yduld1CAKd_lT1iGAsnE4F-W5RMWfaVyzGBiQ9B_gvv-aOvjT

http://zh.wikipedia.org/wiki/GBK

http://ff.163.com/newflyff/gbk-list/

GBK字符集共收录中日韩(CJK)汉字(简繁体)21003个,含少量部首,分布在GBK编码表的2区,3区和4区

其中

------------------------------------------------------------------------------------

GBK 2区(B0A1-F7FE), 收录GB2312汉字共6763个

------------------------------------------------------------------------------------

2区的高位是十进制的176-247, 低位是十进制的161-254

H 176  247

L 161  254

B0  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

A    啊 阿 埃 挨 哎 唉 哀 皑 癌 蔼 矮 艾 碍 爱 隘

B  鞍 氨 安 俺 按 暗 岸 胺 案 肮 昂 盎 凹 敖 熬 翱

C  袄 傲 奥 懊 澳 芭 捌 扒 叭 吧 笆 八 疤 巴 拔 跋

D  靶 把 耙 坝 霸 罢 爸 白 柏 百 摆 佰 败 拜 稗 斑

E  班 搬 扳 般 颁 板 版 扮 拌 伴 瓣 半 办 绊 邦 帮

F  梆 榜 膀 绑 棒 磅 蚌 镑 傍 谤 苞 胞 包 褒 剥

------------------------------------------------------------------------------------

GBK 3区(8140-A0FE), GB13000.1扩充汉字区, 收录CJK(中日韩)汉字6080个

------------------------------------------------------------------------------------

3区的高位是十进制的129-160, 低位是十进制的64-254,其中7F,也就是127没有汉字

H 129  160

L 64   254 (127不要)

81  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

4  丂 丄 丅 丆 丏 丒 丗 丟 丠 両 丣 並 丩 丮 丯 丱

5  丳 丵 丷 丼 乀 乁 乂 乄 乆 乊 乑 乕 乗 乚 乛 乢

6  乣 乤 乥 乧 乨 乪 乫 乬 乭 乮 乯 乲 乴 乵 乶 乷

7  乸 乹 乺 乻 乼 乽 乿 亀 亁 亂 亃 亄 亅 亇 亊

8  亐 亖 亗 亙 亜 亝 亞 亣 亪 亯 亰 亱 亴 亶 亷 亸

9  亹 亼 亽 亾 仈 仌 仏 仐 仒 仚 仛 仜 仠 仢 仦 仧

A  仩 仭 仮 仯 仱 仴 仸 仹 仺 仼 仾 伀 伂 伃 伄 伅

B  伆 伇 伈 伋 伌 伒 伓 伔 伕 伖 伜 伝 伡 伣 伨 伩

C  伬 伭 伮 伱 伳 伵 伷 伹 伻 伾 伿 佀 佁 佂 佄 佅

D  佇 佈 佉 佊 佋 佌 佒 佔 佖 佡 佢 佦 佨 佪 佫 佭

E  佮 佱 佲 併 佷 佸 佹 佺 佽 侀 侁 侂 侅 來 侇 侊

F  侌 侎 侐 侒 侓 侕 侖 侘 侙 侚 侜 侞 侟 価 侢

------------------------------------------------------------------------------------

GBK 4区(AA40-FEA0), GB13000.1扩充汉字区, 收录CJK汉字和增补的汉字8160个(含少量部首)

------------------------------------------------------------------------------------

4区的高位是十进制的170-254, 低位是十进制的64-160,其中7F,也就是127和3区一样没有汉字

H 170  254

L 64   160 (127不要)

AA  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

4  狜 狝 狟 狢 狣 狤 狥 狦 狧 狪 狫 狵 狶 狹 狽 狾

5  狿 猀 猂 猄 猅 猆 猇 猈 猉 猋 猌 猍 猏 猐 猑 猒

6  猔 猘 猙 猚 猟 猠 猣 猤 猦 猧 猨 猭 猯 猰 猲 猳

7  猵 猶 猺 猻 猼 猽 獀 獁 獂 獃 獄 獅 獆 獇 獈

8  獉 獊 獋 獌 獎 獏 獑 獓 獔 獕 獖 獘 獙 獚 獛 獜

9  獝 獞 獟 獡 獢 獣 獤 獥 獦 獧 獨 獩 獪 獫 獮 獰

A  獱

如下函数字符集必须ZHS16GBK

create or replace function func_chinese

(

p_str     in varchar2,     -- 输入的字符串

p_code    in varchar2,     -- dump(字符串)

p_chinese in pls_integer   -- 1, 提取汉字, 非1, 提取非汉字

) return varchar2

as

v_code         varchar2(32767) := substr(p_code,instr(p_code,':')+2);

v_chinese      varchar2(32767) := '';

v_non_chinese  varchar2(32767) := '';

v_comma        pls_integer;

v_code_h       pls_integer;

v_code_l       pls_integer;

begin

if p_str is not null then

for i in 1..length(p_str) loop

if lengthb(substr(p_str,i,1))=2 then

v_comma  := instr(v_code,',');

v_code_h := to_number(substr(v_code,1,v_comma-1));

v_code_l := to_number(substr(v_code,v_comma+1,abs(instr(v_code,',',1,2)-v_comma-1)));

if (v_code_h>=176 and v_code_h<=247 and v_code_l>=161 and v_code_l<=254) or

(v_code_h>=129 and v_code_h<=160 and v_code_l>=64  and v_code_l<=254  and nvl(v_code_l,127)!=127) or

(v_code_h>=170 and v_code_h<=254 and v_code_l>=64  and v_code_l<=160  and nvl(v_code_l,127)!=127) then

v_chinese := v_chinese||substr(p_str,i,1);

else

v_non_chinese := v_non_chinese||substr(p_str,i,1);

end if;

v_code := ltrim(v_code,'1234567890');

v_code := ltrim(v_code,',');

else

v_non_chinese := v_non_chinese||substr(p_str,i,1);

end if;

v_code := ltrim(v_code,'1234567890');

v_code := ltrim(v_code,',');

end loop;

if p_chinese = 1 then

return v_chinese;

else

return v_non_chinese;

end if;

else

return '';

end if;

end;

/

SQL> select * from t;

NAME

----------------------

新年快乐X

狿X

199

春天会来的

-----------------------

实验1: 提取汉字

-----------------------

select name,func_chinese(name,dump(name),1) result from t;

NAME                           RESULT

------------------------------ -----------

新年快乐X                      新年快乐

狿X                            狿

狿                             狿

199

春天会来的                     春天会来的

-----------------------

实验2: 提取非汉字

-----------------------

select name,func_chinese(name,dump(name),0) result from t;

NAME                           RESULT

------------------------------ -------

新年快乐X                      X

狿X                            X

199                            199

春天会来的

-----------------------

实验3: 判断是否都是汉字

-----------------------

select name from t where func_chinese(name,dump(name),0) is null and name is not null;

NAME

-----------

春天会来的

如上函数执行100万次,判断的字符串平均5个汉字,耗时22秒,其中dump耗时6,.5秒,实际判断的字节是10M

同时测试了在字符串很长的时候的性能

测试了字符串都是1000字节,判断1000行需要22秒,实际判断的字节也是10M

总体看,如果用来判断姓名,如果记录很多,性能还可以接受,如果用来判断很长的字符串,且记录很多的时候,性能很差

SQL> select count(*)  from t;

COUNT(*)

----------

1048576

我加了paralle只花了4秒

select /*+ parallel(t 8) */ count(*) from t where func_chinese(name,dump(name),0) is null and name is not null;

COUNT(*)

----------

786432

Elapsed: 00:00:03.94

刚才尝试将v_code := ltrim(v_code,'1234567890'); 去掉,换了一种substr的方法

在字符串很短的时候,性能提升30%,但是字符串很长的时候,性能很糟糕

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值