打印

日文导致Access搜索(80040e14/内存溢出)的解决

==26个日文片假名导致Access搜索(80040e14/内存溢出)的解决办法==

ゴ ガ ギ グ ゲ ザ ジ ズ ヅ デ ド ポ ベ プ ビ パ ヴ ボ ペ ブ ピ バ ヂ ダ ゾ ゼ
当字段内包含了这26个日文字符任意一个多个时,就会导致在执行SQL语句中包含了
[字段] like '%aaaaa%'inStr(1,[字段],'aaaaa',1)>0
这样的查询时,毫无道理的出现了
"Microsoft JET Database Engine 错误 '80040e14' 内存溢出"的错误
其他Jet SQL函数命令未作测试,大概与字符搜索定位匹配相关的都可能出错

搜索相关资料得知被微软工程师证实是Access的bug,可能是语法关系都是微软的东东
在vbs中 执行inStr(1,日文平假名变量,"aaaaa",1)依然要出现错误
Microsoft VBScript 运行时错误 错误 '800a0005' 无效的过程调用或参数: 'instr'


没有搜索,因这几个字符出现Access的论坛网站搜索无法进行,何等痛苦
昨天一朋友大叫怪事,他的音乐数据库无法搜索了,只有30000条记录时是好的
毫无疑问,日文片假名是祸根,花几分钟把有包含上面的日文替换成"?"搜索顺利恢复
找来论坛程序用户群最大的动网dvBBS AC版本 7.0SP2 版测试,同样有这个日文发帖后 导致无法搜索并且运行时出错的问题
线上去搜索 '80040e14' 内存溢出" 的错误 多的是!

一简单有效的解决办法:
对这26个字符进行编码和解码,可能效率感觉不理想,测试下来问题不大,速度影响不是太大

编码:

Function Jencode(byVal iStr)
if isnull(iStr) or isEmpty(iStr) then
  Jencode=""
  Exit function
end if
dim F,i,E
' F=array("ゴ","ガ","ギ","グ","ゲ","ザ","ジ","ズ","ヅ","デ",_
'             "ド","ポ","ベ","プ","ビ","パ","ヴ","ボ","ペ","ブ","ピ","バ",_
'             "ヂ","ダ","ゾ","ゼ")
  E=array("Jn0;","Jn1;","Jn2;","Jn3;","Jn4;","Jn5;","Jn6;","Jn7;","Jn8;","Jn9;","Jn10;","Jn11;","Jn12;","Jn13;","Jn14;","Jn15;","Jn16;","Jn17;","Jn18;","Jn19;","Jn20;","Jn21;","Jn22;","Jn23;","Jn24;","Jn25;")
  F=array(chr(-23116),chr(-23124),chr(-23122),chr(-23120),_
    chr(-23118),chr(-23114),chr(-23112),chr(-23110),_
    chr(-23099),chr(-23097),chr(-23095),chr(-23075),_
    chr(-23079),chr(-23081),chr(-23085),chr(-23087),_
    chr(-23052),chr(-23076),chr(-23078),chr(-23082),_
    chr(-23084),chr(-23088),chr(-23102),chr(-23104),_
    chr(-23106),chr(-23108))
  Jencode=iStr
  for i=0 to 25
   Jencode=replace(Jencode,F(i),E(i))
  next
End Function

解码:

Function Juncode(byVal iStr)
if isnull(iStr) or isEmpty(iStr) then
  Juncode=""
  Exit function
end if
dim F,i,E
' F=array("ゴ","ガ","ギ","グ","ゲ","ザ","ジ","ズ","ヅ","デ",_
'             "ド","ポ","ベ","プ","ビ","パ","ヴ","ボ","ペ","ブ","ピ","バ",_
'             "ヂ","ダ","ゾ","ゼ")
E=array("Jn0;","Jn1;","Jn2;","Jn3;","Jn4;","Jn5;","Jn6;","Jn7;","Jn8;","Jn9;","Jn10;","Jn11;","Jn12;","Jn13;","Jn14;","Jn15;","Jn16;","Jn17;","Jn18;","Jn19;","Jn20;","Jn21;","Jn22;","Jn23;","Jn24;","Jn25;")
  F=array(chr(-23116),chr(-23124),chr(-23122),chr(-23120),_
    chr(-23118),chr(-23114),chr(-23112),chr(-23110),_
    chr(-23099),chr(-23097),chr(-23095),chr(-23075),_
    chr(-23079),chr(-23081),chr(-23085),chr(-23087),_
    chr(-23052),chr(-23076),chr(-23078),chr(-23082),_
    chr(-23084),chr(-23088),chr(-23102),chr(-23104),_
    chr(-23106),chr(-23108))
  Juncode=iStr
for i=0 to 25
  Juncode=replace(Juncode,E(i),F(i))'□
next
End Function

注意,如果直接使用字符不方便(windows还没装日文支持),注释掉的部分提供有 chr(-23804) ..这样的定义

这样
1.
表单输入保存时,使用Jencode()将这26个字符先编码再保存(为什么是这26个字符,经过全部测试87个平假名89个片假名最终认定的)

ゴ 即 chr(-23116) 编码为  Jn1;
2.
显示时,则使用 Juncode() 函数进行解码,还原日文片假名显示
3.
搜索关键字,也要使用 Jencode() 进行编码后再放入 like里
where [Topic] like '%Jencode(kewwords)%'  使用
才能保证搜索的值和编码过的数据库字段内容匹配

==================================

PS:
也可以使用正则表达式来改写上面的两个函数,或许效率还要更高些
再就是如果 压根不使用日文,也不需要搜索日文,则解码部分可以不用,保存数据实直接把这26个片假名字符替换为空字符或任一字符,比如"□"
抛砖引玉,如果有更本质的真正的好方法,谢分享

附:
----------------------------
平假名87个 asc值
-23391 --> -23316
unicode 3040-309F

ぁあぃいぅうぇえぉお
かがきぎくぐけげこご
さざしじすずせぜそぞ
ただちぢっつづてでと
どなにぬねのはばぱひ
びぴふぶぷへべぺほぼ
ぽまみむめもゃやゅゆ
ょよらりるれろゎわゐ
ゑをん゛゜ゝゞ
------------------------------
片假名89个 asc值
-23135 -> -23059
unicode 30A0-30FF

ァアィイゥウェエォオ
カガキギクグケゲコゴ
サザシジスズセゼソゾ
タダチヂッツヅテデト
ドナニヌネノハバパヒ
ビピフブプヘベペホボ
ポマミムメモャヤュユ
ョヨラリルレロヮワヰ
ヱヲンヴヵヶーヽヾ
================补充 修改的版本===========================

添加一个编码解码参数codeType
都使用一个函数
使用chr()不直接使用日文字符
这样~ 够简洁了吧?

疑点: 显示日文是不会出错的,保存到数据库也不会出错
只有SQL使用 like 和 inStr 的时候 才会出错 这个与显示无关!
还有在vbs里使用 inStr(1,str,"aaa",1)这样按字符搜索也会错
改为 inStr(lcase(str),"aaa") 就不会出错

如果一定得用  inStr(1,str,"aaa",1) 字符搜索语法
则一定要在先inStr() 后 jncode() 的顺序 否则会出错

一点问题都没有! 注意到这几点绝对没错!

rs("TopicStr")=Jncode(TopicStr,true)  'encode 保存到数据库的资料
DisplayStr=Jncode(rs("TopicStr"),false) 'uncode       '显示到页面的标题

Function Jncode(byVal iStr,codeType)
       if isnull(iStr) or isEmpty(iStr) or iStr="" then
              Jncode=""
              Exit function
       end if
       dim F,i,E
              E=array("Jn0;","Jn1;","Jn2;","Jn3;","Jn4;","Jn5;","Jn6;",_
                            "Jn7;","Jn8;","Jn9;","Jn10;","Jn11;","Jn12;","Jn13;",_
                            "Jn14;","Jn15;","Jn16;","Jn17;","Jn18;","Jn19;","Jn20;",_
                            "Jn21;","Jn22;","Jn23;","Jn24;","Jn25;")
              F=array(chr(-23116),chr(-23124),chr(-23122),chr(-23120),_
                            chr(-23118),chr(-23114),chr(-23112),chr(-23110),_
                            chr(-23099),chr(-23097),chr(-23095),chr(-23075),_
                            chr(-23079),chr(-23081),chr(-23085),chr(-23087),_
                            chr(-23052),chr(-23076),chr(-23078),chr(-23082),_
                            chr(-23084),chr(-23088),chr(-23102),chr(-23104),_
                            chr(-23106),chr(-23108))
       if codyType then
               for i=0 to 25
               iStr=replace(iStr,F(i),E(i))'□
               next
       else
               for i=0 to 25
                iStr=replace(iStr,E(i),F(i))'□
               next
       end if
       Jncode=iStr
End Function

================补充 修改的版本2 改用unicode===========================

添加一个编码解码参数codeType
都使用一个函数
使用chr()不直接使用日文字符
这样~ 够简洁了吧?

疑点: 显示日文是不会出错的,保存到数据库也不会出错
只有SQL使用 like 和 inStr 的时候 才会出错 这个与显示无关!
还有在vbs里使用 inStr(1,str,"aaa",1)这样按字符搜索也会错
改为 inStr(lcase(str),"aaa") 就不会出错

如果一定得用  inStr(1,str,"aaa",1) 字符搜索语法
则一定要在先inStr() 后 jncode() 的顺序 否则会出错

一点问题都没有! 注意到这几点绝对没错!

rs("TopicStr")=Jncode(TopicStr,true)  'encode 保存到数据库的资料
DisplayStr=Jncode(rs("TopicStr"),false) 'uncode '显示到页面的标题

Function Jncode(byVal iStr,codeType)
if isnull(iStr) or isEmpty(iStr) or iStr="" then
  Jncode="" : Exit function
end if
dim F,i,E
  E=array("Jn0;","Jn1;","Jn2;","Jn3;","Jn4;","Jn5;","Jn6;",_
    "Jn7;","Jn8;","Jn9;","Jn10;","Jn11;","Jn12;","Jn13;",_
    "Jn14;","Jn15;","Jn16;","Jn17;","Jn18;","Jn19;","Jn20;",_
    "Jn21;","Jn22;","Jn23;","Jn24;","Jn25;")
  F=array(chrw(12468),chrw(12460),chrw(12462),chrw(12464),_
    chrw(12466),chrw(12470),chrw(12472),chrw(12474),_
    chrw(12485),chrw(12487),chrw(12489),chrw(12509),_
    chrw(12505),chrw(12503),chrw(12499),chrw(12497),_
    chrw(12532),chrw(12508),chrw(12506),chrw(12502),_
    chrw(12500),chrw(12496),chrw(12482),chrw(12480),_
    chrw(12478),chrw(12476))
if codyType then
   for i=0 to 25 iStr=replace(iStr,F(i),E(i)) next
else
   for i=0 to 25 iStr=replace(iStr,E(i),F(i)) next
end if
Jncode=iStr
End Function


===========================================
Blueidea.com web team member V37(PaintBlue.Net) / 转贴注明出处
本帖最近评分记录
非一所思~~
PaintBlue.NET
高手出招,与世俱惊!
的确是个好的解决方法
呵呵!  http://www.loveyuki.com/blogview.asp?logID=621&cateID=4

因为懒,少写了几句话! 造成V37的误会,真是很抱歉!
The Matrix Reloaded.
http://www.loveyuki.com

TOP

这个是很盛行的搜索Bug啦
不是asp的问题 是 Jet SQL 的问题

好费解的bug
非一所思~~
PaintBlue.NET

TOP

loveyuki在上个帖子中说楼上怀疑原创性吗?
这个 http://bbs.blueidea.com/viewthread.php?tid=1741998

你的blog帖子根本没看到过,压根没去过
纯粹巧合,偶是为解决自己的论坛因有日文无法搜索和发帖 才弄的这个!
26个字符也是试验出来的 试完后才想起应该写一段检测程序一次就全部过滤出来
这纯粹闭门造车出来的,内容也无多少技术含量,不过我相信这是很实际有哟难的解决办法

不过争辩也无意义,我看重的是实际解决问题后心情舒畅
非一所思~~
PaintBlue.NET

TOP

V37在上个帖子中说
引用:
loveyuki在上个帖子中说
[quote] 呵呵!  http://www.loveyuki.com/blogview.asp?logID=621&cateID=4
楼上怀疑原创性吗?
这个 http://bbs.blueidea.com/viewthread.php?tid=1741998

你的blog帖子根本没看到过,压根没去过
纯粹巧合,偶是为解决自己的论坛因有日文无法搜索和发帖 才弄的这个!
26个字符也是试验出来的 试完后才想起应该写一段检测程序一次就全部过滤出来
这纯粹闭门造车出来的,内容也无多少技术含量,不过我相信这是很实际有哟难的解决办法

不过争辩也无意义,我看重的是实际解决问题后心情舒畅
[/quote]

当然不是,我只是说我也发现了,但是一直没有着手去解决而以!本来想转你的帖子,但是你也知道搜索出错!而且替换法也不能根治,因为替换后,发表这样的帖子就不成了!
The Matrix Reloaded.
http://www.loveyuki.com

TOP

呵呵,我误解你了
抱歉抱歉

替换法还是不错的,因为你无法避免别人在你站上发含片假名的 帖子
否则马上你的站上搜索瘫痪 可怕的事
你发主题时都使用一张图片,哈哈~~~~~~ 窝火吧!!

而编码只针对 需要使用 like 的字段 这个比较少的 一般就是  主题 会员名 和文章内容
用的最多的是文章主题 会员名是管理会员才用 注册时过滤掉这 26个字符也可以省去处理会员的解码

就像国外空间使用 cookies的编码解码一样
没办法的办法

如果转帖去掉26个日文字符部分使用
F=array(chr(-23116),chr(-23124),chr(-23122),。。。。。
这句,因为直接使用 字符比用chr(-23116) 少一次函数调用,自然要快一些



非一所思~~
PaintBlue.NET

TOP

V37在上个帖子中说
引用:
呵呵,我误解你了
抱歉抱歉

替换法还是不错的,因为你无法避免别人在你站上发含片假名的 帖子
否则马上你的站上搜索瘫痪 可怕的事
你发主题时都使用一张图片,哈哈~~~~~~ 窝火吧!!

而编码只针对 需要使用 like 的字段 这个比较少的 一般就是  主题 会员名 和文章内容
用的最多的是文章主题 会员名是管理会员才用 注册时过滤掉这 26个字符也可以省去处理会员的解码

就像国外空间使用 cookies的编码解码一样
没办法的办法

如果转帖去掉26个日文字符部分使用
F=array(chr(-23116),chr(-23124),chr(-23122),。。。。。
这句,因为直接使用 字符比用chr(-23116) 少一次函数调用,自然要快一些
呵呵,最初还是我的错!
现在得想办法解决替换会出的问题!就像你写的那段代码,如果用替换法!
E=array("Jn0;","Jn1;","Jn2;","Jn3;","Jn4;","Jn5;","Jn6;","Jn7;","Jn8;","Jn9;","Jn10;","Jn11;","Jn12;","Jn13;","Jn14;","Jn15;","Jn16;","Jn17;","Jn18;","Jn19;","Jn20;","Jn21;","Jn22;","Jn23;","Jn24;","Jn25;")
这句就会变成
E=array("ゴ","ガ","ギ","グ","ゲ","ザ","ジ","ズ","ヅ","デ", "ド","ポ","ベ","プ","ビ","パ","ヴ","ボ","ペ","ブ","ピ","バ", "ヂ","ダ","ゾ","ゼ")

因为显示的时候会替换过来!。。。
The Matrix Reloaded.
http://www.loveyuki.com

TOP

高手,学习中....

TOP

to loveyuki

这样,添加一个编码解码参数codeType
都使用一个函数
使用chr()不直接使用日文字符
这样~ 够简洁了吧?

疑点: 显示日文是不会出错的,保存到数据库也不会出错
只有SQL使用 like 和 inStr 的时候 才会出错 这个与显示无关!
还有在vbs里使用 inStr(1,str,"aaa",1)这样按字符搜索也会错
改为 inStr(lcase(str),"aaa") 就不会出错

如果一定得用  inStr(1,str,"aaa",1) 字符搜索语法
则一定要在先inStr() 后 jncode() 的顺序 否则会出错

一点问题都没有! 注意到这几点绝对没错!

rs("TopicStr")=Jncode(TopicStr,true)  'encode 保存到数据库的资料
DisplayStr=Jncode(rs("TopicStr"),false) 'uncode       '显示到页面的标题

Function Jncode(byVal iStr,codeType)
       if isnull(iStr) or isEmpty(iStr) or iStr="" then
              Jncode="" : Exit function
       end if
       dim F,i,E
              E=array("Jn0;","Jn1;","Jn2;","Jn3;","Jn4;","Jn5;","Jn6;",_
                            "Jn7;","Jn8;","Jn9;","Jn10;","Jn11;","Jn12;","Jn13;",_
                            "Jn14;","Jn15;","Jn16;","Jn17;","Jn18;","Jn19;","Jn20;",_
                            "Jn21;","Jn22;","Jn23;","Jn24;","Jn25;")
              F=array(chr(-23116),chr(-23124),chr(-23122),chr(-23120),_
                            chr(-23118),chr(-23114),chr(-23112),chr(-23110),_
                            chr(-23099),chr(-23097),chr(-23095),chr(-23075),_
                            chr(-23079),chr(-23081),chr(-23085),chr(-23087),_
                            chr(-23052),chr(-23076),chr(-23078),chr(-23082),_
                            chr(-23084),chr(-23088),chr(-23102),chr(-23104),_
                            chr(-23106),chr(-23108))
       if codyType then
               for i=0 to 25 iStr=replace(iStr,F(i),E(i)) next
       else
               for i=0 to 25 iStr=replace(iStr,E(i),F(i)) next
       end if
       Jncode=iStr
End Function
非一所思~~
PaintBlue.NET

TOP

呵呵,高手过招。

TOP

实在不放心替换成HTML编码



uincode码为
为 30BA  十进制 12474

于是
使用html编码 为 ズ

这26个字符全替换成 &#xxxxx; 格式的 HTML编码
则可以显示为日文,代码无直接日文字符
如果显示没有用到 Server.HTMLencode 则可以直接编码为 &#xxxxx;
解码也不用了


非一所思~~
PaintBlue.NET

TOP

强呀。。。
我一直哭一直哭,哭我没鞋穿。直到有一天我看到一个人,他连脚也没有……

TOP

这样做系统开销太大了啊,真的没有更好的方法了吗,有谁知道日本人他们自己是怎么解决的,太郁闷了!
我很坏!

TOP