[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[其他] [分享]“if 依据字典顺序进行字符比较”的猜测和验证

本帖最后由 CrLf 于 2011-11-27 12:19 编辑

if 的排序规则一直让人困扰,它既不遵从 nls 代码页文件的字符顺序,也不遵从 gbk 或者 unicode 的编码顺序,昨天从个人收藏中翻出一份“汉字编码.txt”(某位大师给的,一直没用上,差点忘了...),忽然想起 if 的字符排序是否和字典里的拼音顺序吻合?这个说法是可以解释得了英文字母为何会出现 A lss b 的现象的,那放在汉字环境中是否也成立呢?
于是着手测试,小规模手工粗筛结果初步证明了这一点(比如 if 啊 lss 吧 if 吧 lss 嚓 echo 啊 lss 吧 lss 嚓)。
看来颇有希望,而要进行缜密的验证,需要把“汉字编码.txt”处理成易于解读的格式,于是进行了为时 N 小时的痛苦处理(愿意看处理全程的筒子可以看 2 楼)...
在处理“汉字编码.txt”的过程中,通过对字符顺序的比较,证明 if 对汉字进行字符比较时确实是依照拼音顺序排序的,于是顺便写了一个汉字转拼音的小脚本(不判断多音字):

所用到的简表“汉字拼音与排序.txt”(就是刚生成的 11.txt,规格是“拼音a的第一个汉字 a 拼音ai的第一个汉字 ai 拼音an的第一个汉字...”):
  1. 吖 a 埃 ai 氨 an 肮 ang 凹 ao 芭 ba 白 bai 班 ban 邦 bang 苞 bao 杯 bei 奔 ben 崩 beng 逼 bi 边 bian 标 biao 憋 bie 彬 bin 冰 bing 玻 bo 卜 bu 擦 ca 猜 cai 参 can 苍 cang 操 cao 厕 ce 岑 cen 层 ceng 叉 cha 拆 chai 掺 chan 猖 chang 朝 chao 车 che 臣 chen 城 cheng 痴 chi 虫 chong 畴 chou 厨 chu 搋 chuai 穿 chuan 窗 chuang 炊 chui 椿 chun 辍 chuo 茨 ci 葱 cong 凑 cou 粗 cu 蹿 cuan 崔 cui 村 cun 磋 cuo 搭 da 呆 dai 担 dan 当 dang 刀 dao 得 de 灯 deng 低 di 嗲 dia 掂 dian 叼 diao 爹 die 丁 ding 丢 diu 东 dong 都 dou 督 du 端 duan 堆 dui 吨 dun 哆 duo 峨 e 诶 ei 恩 en 儿 er 发 fa 帆 fan 坊 fang 非 fei 芬 fen 丰 feng 佛 fo 缶 fou 夫 fu 嘎 ga 该 gai 甘 gan 冈 gang 皋 gao 哥 ge 给 gei 根 gen 耕 geng 工 gong 勾 gou 菇 gu 瓜 gua 乖 guai 关 guan 光 guang 规 gui 辊 gun 郭 guo 哈 ha 孩 hai 酣 han 夯 hang 壕 hao 呵 he 黑 hei 痕 hen 亨 heng 轰 hong 侯 hou 乎 hu 花 hua 徊 huai 欢 huan 荒 huang 灰 hui 昏 hun 锪 huo 击 ji 枷 jia 歼 jian 姜 jiang 椒 jiao 接 jie 巾 jin 荆 jing 炯 jiong 究 jiu 拘 ju 捐 juan 撅 jv 均 jun 咖 ka 开 kai 刊 kan 康 kang 考 kao 苛 ke 肯 ken 坑 keng 空 kong 抠 kou 枯 ku 夸 kua 块 kuai 宽 kuan 匡 kuang 亏 kui 坤 kun 扩 kuo 垃 la 来 lai 婪 lan 琅 lang 捞 lao 乐 le 雷 lei 棱 leng 厘 li 莲 lian 凉 liang 聊 liao 列 lie 林 lin 玲 ling 溜 liu 龙 long 娄 lou 卢 lu 峦 luan 抡 lun 萝 luo 驴 lv 略 lve 妈 ma 埋 mai 馒 man 芒 mang 猫 mao 么 me 玫 mei 门 men 萌 meng 眯 mi 眠 mian 苗 miao 灭 mie 民 min 明 ming 谬 miu 摸 mo 牟 mou 姆 mu 拿 na 乃 nai 男 nan 囊 nang 挠 nao 讷 ne 馁 nei 嫩 nen 能 neng 妮 ni 拈 nian 娘 niang 鸟 niao 捏 nie 您 nin 狞 ning 牛 niu 浓 nong 耨 nou 奴 nu 暖 nuan 挪 nuo 钕 nve 女 nv 噢 o 欧 ou 趴 pa 拍 pai 潘 pan 乓 pang 抛 pao 呸 pei 喷 pen 抨 peng 坯 pi 偏 pian 漂 piao 瞥 pie 拼 pin 乒 ping 坡 po 剖 pou 扑 pu 期 qi 掐 qia 扦 qian 枪 qiang 锹 qiao 切 qie 钦 qin 青 qing 穷 qiong 丘 qiu 区 qu 圈 quan 炔 qv 裙 qun 然 ran 瓤 rang 饶 rao 惹 re 壬 ren 扔 reng 日 ri 戎 rong 柔 rou 茹 ru 阮 ruan 蕊 rui 闰 run 若 ruo 洒 sa 腮 sai 三 san 桑 sang 搔 sao 色 se 森 sen 僧 seng 砂 sha 筛 shai 苫 shan 伤 shang 捎 shao 奢 she 申 shen 生 sheng 失 shi 收 shou 枢 shu 刷 shua 衰 shuai 拴 shuan 双 shuang 谁 shui 吮 shun 说 shuo 斯 si 松 song 搜 sou 苏 su 酸 suan 虽 sui 孙 sun 梭 suo 他 ta 胎 tai 坍 tan 汤 tang 涛 tao 忒 te 腾 teng 剔 ti 天 tian 挑 tiao 贴 tie 厅 ting 通 tong 偷 tou 凸 tu 湍 tuan 推 tui 吞 tun 乇 tuo 挖 wa 歪 wai 弯 wan 汪 wang 威 wei 温 wen 翁 weng 挝 wo 巫 wu 昔 xi 虾 xia 掀 xian 相 xiang 萧 xiao 些 xie 芯 xin 星 xing 凶 xiong 休 xiu 戌 xu 轩 xuan 靴 xv 勋 xun 压 ya 咽 yan 央 yang 腰 yao 椰 ye 一 yi 茵 yin 英 ying 哟 yo 佣 yong 优 you 迂 yu 鸳 yuan 曰 yv 云 yun 匝 za 哉 zai 咱 zan 赃 zang 遭 zao 责 ze 贼 zei 怎 zen 增 zeng 扎 zha 摘 zhai 毡 zhan 章 zhang 招 zhao 遮 zhe 珍 zhen 蒸 zheng 芝 zhi 中 zhong 舟 zhou 珠 zhu 抓 zhua 拽 zhuai 专 zhuan 庄 zhuang 椎 zhui 谆 zhun 拙 zhuo 咨 zi 棕 zong 邹 zou 租 zu 纂 zuan 嘴 zui 尊 zun 昨 zuo
复制代码
实际代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. set input=汉字转拼音测试
  3. set /p input=Input:
  4. for /f "delims=" %%a in (汉字拼音与排序.txt) do (
  5.         for /l %%b in (0 1 8185) do (
  6.                 rem 变量最长 8192 字符,减去变量名和空格,input 变量内容最长为 8186 字符
  7.                 if "!input:~%%b!" neq "" (
  8.                         set py=
  9.                         if !input:~%%b! geq 吖 if !input:~%%b! leq 咗 (
  10.                         rem 检测是否是汉字,在 nls 表中,汉字的范围是从吖到咗(小~大)
  11.                                 set str=%%a
  12.                                 set py=zuo
  13.                                 for /l %%c in (1 1 402) do (
  14.                                 rem 表中共有 402 个拼音,故用 402 次循环
  15.                                         for /f "tokens=1,2,3*" %%d in ("!str!") do (
  16.                                                 if !input:~%%b! geq %%d if !input:~%%b! lss %%f (
  17.                                                 rem 逐个进行字符比较,查找该汉字是在哪个拼音的范围之内 %%d 为下限,%%e 为拼音,%%f 为上限
  18.                                                         set py=%%e&set str=
  19.                                                 )
  20.                                                 if defined str set str=%%f %%g
  21.                                                 rem 当符合条件时清空 str 变量终止循环,减少内层循环次数
  22.                                         )
  23.                                 )
  24.                                 set var=!var! !py!
  25.                         )
  26.                         if not defined py set "var=!var!!input:~%%b,1!"
  27.                         rem 当该字不为表内汉字时,则附加在输出内容中
  28.                 )
  29.         )
  30.         echo;!var!
  31. )<nul
  32. pause
复制代码
当然也可以作为函数调用,翻译《归去来兮辞》的实例如下:
  1. @echo off&setlocal enabledelayedexpansion
  2. echo %time%
  3. for %%a in (汉字转拼音测试:
  4. "                《归去来兮辞》陶渊明"
  5. "    归去来兮!田园将芜胡不归?既自以心为形役,奚惆怅而独悲?悟已往之不谏,知来者之可追;实迷途其未远,觉今是而昨非。舟遥遥以轻飏,风飘飘而吹衣。问征夫以前路,恨晨光之熹微。"
  6. "    乃瞻衡宇,载欣载奔。僮仆欢迎,稚子候门。三径就荒,松菊犹存。携幼入室,有酒盈樽。引壶觞以自酌,眄庭柯以怡颜。倚南窗以寄傲,审容膝之易安。园日涉以成趣,门虽设而常关。策扶老以流憩,时矫首而遐观。云无心以出岫,鸟倦飞而知还。景翳翳以将入,抚孤松而盘桓。"
  7. "    归去来兮!请息交以绝游。世与我而相违,复驾言兮焉求?悦亲戚之情话,乐琴书以消忧。农人告余以春及,将有事于西畴。或命巾车,或棹孤舟。既窈窕以寻壑,亦崎岖而经丘。木欣欣以向荣,泉涓涓而始流。善万物之得时,感吾生之行休。"
  8. "    已矣乎!寓形宇内复几时,曷不委心任去留?胡为乎遑遑欲何之?富贵非吾愿,帝乡不可期。怀良辰以孤往,或植杖而耘耔。登东皋以舒啸,临清流而赋诗。聊乘化以归尽,乐夫天命复奚疑! "
  9. ) do call :hz2py %%a&echo;
  10. echo %time%
  11. pause
  12. :hz2py
  13. setlocal enabledelayedexpansion
  14. set "input=%~1"
  15. for /f "delims=" %%a in (汉字拼音与排序.txt) do (
  16.         for /l %%b in (0 1 8185) do (
  17.                 if "!input:~%%b!" neq "" (
  18.                         set py=
  19.                         if !input:~%%b! geq 吖 if !input:~%%b! leq 咗 (
  20.                                 set str=%%a
  21.                                 set py=zuo
  22.                                 for /l %%c in (1 1 402) do (
  23.                                         for /f "tokens=1,2,3*" %%d in ("!str!") do (
  24.                                                 if !input:~%%b! geq %%d if !input:~%%b! lss %%f (
  25.                                                         set py=%%e&set str=
  26.                                                 )
  27.                                                 if defined str set str=%%f %%g
  28.                                         )
  29.                                 )
  30.                                 set var=!var! !py!
  31.                         )
  32.                         if not defined py set "var=!var!!input:~%%b,1!"
  33.                 )
  34.         )
  35.         echo;!var!
  36. )<nul
  37. endlocal
复制代码
可以看到,利用 if 字符判断,成功地将汉字转换成了拼音,虽然无法判断多音字,但是已经证明了 if 的字符比较在碰到文字(汉字、英文)时是依照字典顺序进行排列的,可以确定的是,if 比较肯定是查表的,而且系统中也存在一个类似 nls 的“字典”,只是其中的语言文字是按照音标顺序排列的。

注:后来证明,排序方式是由区域语言设置来设置的,而保存汉字拼音具体顺序的字典则是 system32 文件夹下的 .nls 文件。(nls 相关内容详见 5 楼链接)
附件: 您需要登录才可以下载或查看附件。没有帐号?注册

写了一个验证排序的C程序

http://bbs.bathome.net/viewthread.php?tid=18542

TOP

if的排序规则即lstrcmp函数的排序规则(详见《批处理技术内幕:IF命令》),而lstrcmp函数的排序规则与当前线程的Locale有关。

TOP

回复 9# CrLf


比如:
定义很多大数组
open的文件不close
生成的对象不销毁
等等

TOP

回复 8# HAT


    原来如此...不过不知内存占用主要受什么影响呢?

TOP

回复 4# CrLf


空间复杂度:内存占用情况
时间复杂度:程序运行时间的长短
1

评分人数

    • CrLf: 多谢指点PB + 3

TOP

可以参考:sort的l参数的
/l locale
替代由系统默认区域设置(即在安装时选择的语言和“国家(地区)”)定义的字符排序顺序。
1

评分人数

    • CrLf: 感谢提示!PB + 5
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

刚才 zqz0012005 提出并且证明了此处的顺序依据的是系统语言设置:
一、控制面板>区域和语言选项>自定义此格式(自定义区域选项)>排序>拼音/比划
二、注册表>"HKUS\用户SID\Control Panel\International\"下的"LocaleName"键值,若为 zh-CN 则是汉语拼音顺序,zh-CN_stroke 则是汉字笔画顺序。
我验证后的测试结果果然和他的猜测相符,所以,if 字符比较的排序依据应该是与系统中所设语言的字符排序一致的,文件、文件夹等也是以此排序。

TOP

SOS --- >> lllsoslll@163.com

TOP

本帖最后由 CrLf 于 2011-11-14 19:00 编辑

回复 3# lllsoslll


    汗...看不到代码...空间复杂度和时间复杂度是什么呀?

TOP

受启发写个批处理汉字转拼音,算法时间复杂度O(n),空间复杂度O(1);
本代码仅高人可见:
SOS --- >> lllsoslll@163.com

TOP

处理“汉字编码.txt”的全过程:
  1. sed "y/abcdefghijklmnopqrstuüwxyz/abcdefghijklmnopqrstuvwxyz/" 汉字编码.txt>2.txt
  2. :: 替换拼音为英文字符
复制代码
  1. sed -n "H;/^$/{x;s/\n/ /g;p;s/.*//;x}" 2.txt>3.txt
  2. ::合并拼音与其对应内容为一行
复制代码
  1. sed "s/[0-9]//g;s/ *[a-z]  返回↑/\n /g;s/ *$//g;s/  / /g" 3.txt>4.txt
  2. ::去除多余内容
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. (for /f "tokens=1*" %%a in (4.txt) do (
  3. set max=&set min=祚
  4. for %%c in (%%b) do (
  5. if %%c lss !min! set min=%%c
  6. if %%c gtr !max! set max=%%c
  7. )>con
  8. if !min! gtr !lax! echo %%a !min!>>6.txt
  9. set lax=!max!
  10. set lin=!min!
  11. echo %%a@!min!@!max!
  12. ))>5.txt
  13. pause
  14. ::分别提取每个拼音的最大最小字符到 5.txt 和 6.txt
复制代码
  1. sed -n "H;${g;s/\n/ /g;p}" 6.txt>7.txt
  2. ::合并行
复制代码
  1. ::生成 8.txt 时以为大功告成,结果发现字符顺序有误(有多音字的原因)导致结果出错,代码未保留。
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. set lit=吖
  3. set input=埃 挨 哎 唉 哀 皑 癌 蔼 矮 艾 碍 爱 隘 捱 嗳 嗌 嫒 瑷 暧 砹 锿 霭
  4. set lpy=ai
  5. for /f "skip=2 delims=" %%A in (4处理.txt) do (
  6. set str=
  7. for /f "tokens=1*" %%B in ("%%A") do set py=%%B&set next=%%C
  8. for /f %%a in ("!next!") do set big=%%a
  9. echo !lit!~!big!:!input!
  10. for %%a in (!input! !G!) do (
  11. if %%a gtr !lit! (
  12. if %%a lss !big! (
  13. set str=!str! %%a
  14. set G=!G: %%a=!
  15. ) else echo G %%a&set G=!G: %%a=! %%a
  16. ) else echo L %%a&set /p=%%a <nul>>Lit.txt
  17. )
  18. echo>>9.txt  !lpy! !str!
  19. echo @!str!@
  20. for /f %%B in ("!input!") do set lit=%%B
  21. set input=!next!
  22. set lpy=!py!
  23. echo;
  24. pause
  25. cls
  26. )
  27. pause
  28. ::重新排序,将位置超前的字符安置到相应的拼音下,而位置滞后的字符输出到 Lit.txt 准备进行手工处理,生成 9.txt
复制代码
  1. ::手工处理,将 Lit.txt 中的字符按其可能的拼音依次尝试,补全 9.txt 中缺失的内容。
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. set A=吖
  3. for /f "skip=1 tokens=2" %%a in (9.txt) do (
  4. if !A! lss %%a (echo !A! lss %%a) else echo !A! gtr %%a!!!!!!!&echo !A! lss %%a>>10.txt
  5. set A=%%a
  6. pause
  7. )
  8. echo end
  9. ping /t localhost>nul
  10. ::修正拼音顺序,生成 10.txt,用于对 9.txt 纠错
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. (for /f "tokens=1*" %%a in (9.txt) do (
  3. set str=%%b
  4. for /f %%c in ("%%b") do set last=%%c
  5. for %%c in (%%a) do (
  6. for %%d in (!str!) do (
  7. if %%d lss !last! (
  8. for %%e in (!last!) do (
  9. set str=!str:%%e %%d=%%d %%e!
  10. set last=%%e
  11. )
  12. ) else set last=%%d
  13. )
  14. )
  15. echo %%a !str!
  16. ))>11.txt
  17. pause
  18. ::修正行内汉字顺序为从小到大
复制代码
  1. @echo off
  2. (for /f "tokens=1,2" %%a in (11.txt) do set /p=%%b %%a )<nul>12.txt
  3. ::再手工加上 11.txt 中的最后一个汉字作为拼音 zuo 的上限。历经 11 关磨难,终于搞定,泪奔...
复制代码

TOP

返回列表