==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) ..這樣的定義 [page_break] 這樣 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
========================================================================== [page_break]這是在網上摘抄的,太多,看了還是不曉得解決,后來又繼續翻了一把,發現一個工具,讓我跌了一下眼鏡,代碼如下: <% '檢查有日文片假名的新聞 Server.ScriptTimeout=300 dim conn,str,rs, sql set conn=server.createobject("adodb.connection") set rs=server.createobject("adodb.recordset") str="provider=Microsoft.Jet.OLEDB.4.0; Data Source="+Server.MapPath("data/xsjnews.asa") conn.open str sql="select newsid from news" rs.open sql,conn,1,1 on error resume next do until rs.eof sql="select newsid from news where (title like 'a' or content like 'a') and newsid = "& rs("newsid") Err=0 conn.execute(sql) if not Err=0 then Response.Write "錯誤新聞ID:" Response.Write rs("newsid") Response.Write "<br>" Err=0 'sql = "delete * from news where newsid ="& rs("newsid") 'conn.execute(sql) end if rs.movenext loop rs.close conn.close response.write "查找完成" %>
|