标题: [其他] [分享]“if 依据字典顺序进行字符比较”的猜测和验证 [打印本页]
作者: CrLf 时间: 2011-11-14 14:21 标题: [分享]“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 对汉字进行字符比较时确实是依照拼音顺序排序的,于是顺便写了一个汉字转拼音的小脚本(不判断多音字):
[attach]4722[/attach][attach]4668[/attach]
所用到的简表“汉字拼音与排序.txt”(就是刚生成的 11.txt,规格是“拼音a的第一个汉字 a 拼音ai的第一个汉字 ai 拼音an的第一个汉字...”):- 吖 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
复制代码
实际代码:- @echo off&setlocal enabledelayedexpansion
- set input=汉字转拼音测试
- set /p input=Input:
- for /f "delims=" %%a in (汉字拼音与排序.txt) do (
- for /l %%b in (0 1 8185) do (
- rem 变量最长 8192 字符,减去变量名和空格,input 变量内容最长为 8186 字符
- if "!input:~%%b!" neq "" (
- set py=
- if !input:~%%b! geq 吖 if !input:~%%b! leq 咗 (
- rem 检测是否是汉字,在 nls 表中,汉字的范围是从吖到咗(小~大)
- set str=%%a
- set py=zuo
- for /l %%c in (1 1 402) do (
- rem 表中共有 402 个拼音,故用 402 次循环
- for /f "tokens=1,2,3*" %%d in ("!str!") do (
- if !input:~%%b! geq %%d if !input:~%%b! lss %%f (
- rem 逐个进行字符比较,查找该汉字是在哪个拼音的范围之内 %%d 为下限,%%e 为拼音,%%f 为上限
- set py=%%e&set str=
- )
- if defined str set str=%%f %%g
- rem 当符合条件时清空 str 变量终止循环,减少内层循环次数
- )
- )
- set var=!var! !py!
- )
- if not defined py set "var=!var!!input:~%%b,1!"
- rem 当该字不为表内汉字时,则附加在输出内容中
- )
- )
- echo;!var!
- )<nul
- pause
复制代码
当然也可以作为函数调用,翻译《归去来兮辞》的实例如下:- @echo off&setlocal enabledelayedexpansion
- echo %time%
- for %%a in (汉字转拼音测试:
- " 《归去来兮辞》陶渊明"
- " 归去来兮!田园将芜胡不归?既自以心为形役,奚惆怅而独悲?悟已往之不谏,知来者之可追;实迷途其未远,觉今是而昨非。舟遥遥以轻飏,风飘飘而吹衣。问征夫以前路,恨晨光之熹微。"
- " 乃瞻衡宇,载欣载奔。僮仆欢迎,稚子候门。三径就荒,松菊犹存。携幼入室,有酒盈樽。引壶觞以自酌,眄庭柯以怡颜。倚南窗以寄傲,审容膝之易安。园日涉以成趣,门虽设而常关。策扶老以流憩,时矫首而遐观。云无心以出岫,鸟倦飞而知还。景翳翳以将入,抚孤松而盘桓。"
- " 归去来兮!请息交以绝游。世与我而相违,复驾言兮焉求?悦亲戚之情话,乐琴书以消忧。农人告余以春及,将有事于西畴。或命巾车,或棹孤舟。既窈窕以寻壑,亦崎岖而经丘。木欣欣以向荣,泉涓涓而始流。善万物之得时,感吾生之行休。"
- " 已矣乎!寓形宇内复几时,曷不委心任去留?胡为乎遑遑欲何之?富贵非吾愿,帝乡不可期。怀良辰以孤往,或植杖而耘耔。登东皋以舒啸,临清流而赋诗。聊乘化以归尽,乐夫天命复奚疑! "
- ) do call :hz2py %%a&echo;
- echo %time%
- pause
- :hz2py
- setlocal enabledelayedexpansion
- set "input=%~1"
- for /f "delims=" %%a in (汉字拼音与排序.txt) do (
- for /l %%b in (0 1 8185) do (
- if "!input:~%%b!" neq "" (
- set py=
- if !input:~%%b! geq 吖 if !input:~%%b! leq 咗 (
- set str=%%a
- set py=zuo
- for /l %%c in (1 1 402) do (
- for /f "tokens=1,2,3*" %%d in ("!str!") do (
- if !input:~%%b! geq %%d if !input:~%%b! lss %%f (
- set py=%%e&set str=
- )
- if defined str set str=%%f %%g
- )
- )
- set var=!var! !py!
- )
- if not defined py set "var=!var!!input:~%%b,1!"
- )
- )
- echo;!var!
- )<nul
- endlocal
复制代码
可以看到,利用 if 字符判断,成功地将汉字转换成了拼音,虽然无法判断多音字,但是已经证明了 if 的字符比较在碰到文字(汉字、英文)时是依照字典顺序进行排列的,可以确定的是,if 比较肯定是查表的,而且系统中也存在一个类似 nls 的“字典”,只是其中的语言文字是按照音标顺序排列的。
注:后来证明,排序方式是由区域语言设置来设置的,而保存汉字拼音具体顺序的字典则是 system32 文件夹下的 .nls 文件。(nls 相关内容详见 5 楼链接)
作者: CrLf 时间: 2011-11-14 14:24
处理“汉字编码.txt”的全过程:- sed "y/abcdefghijklmnopqrstuüwxyz/abcdefghijklmnopqrstuvwxyz/" 汉字编码.txt>2.txt
- :: 替换拼音为英文字符
复制代码
- sed -n "H;/^$/{x;s/\n/ /g;p;s/.*//;x}" 2.txt>3.txt
- ::合并拼音与其对应内容为一行
复制代码
- sed "s/[0-9]//g;s/ *[a-z] 返回↑/\n /g;s/ *$//g;s/ / /g" 3.txt>4.txt
- ::去除多余内容
复制代码
- @echo off&setlocal enabledelayedexpansion
- (for /f "tokens=1*" %%a in (4.txt) do (
- set max=&set min=祚
- for %%c in (%%b) do (
- if %%c lss !min! set min=%%c
- if %%c gtr !max! set max=%%c
- )>con
- if !min! gtr !lax! echo %%a !min!>>6.txt
- set lax=!max!
- set lin=!min!
- echo %%a@!min!@!max!
- ))>5.txt
- pause
- ::分别提取每个拼音的最大最小字符到 5.txt 和 6.txt
复制代码
- sed -n "H;${g;s/\n/ /g;p}" 6.txt>7.txt
- ::合并行
复制代码
- ::生成 8.txt 时以为大功告成,结果发现字符顺序有误(有多音字的原因)导致结果出错,代码未保留。
复制代码
- @echo off&setlocal enabledelayedexpansion
- set lit=吖
- set input=埃 挨 哎 唉 哀 皑 癌 蔼 矮 艾 碍 爱 隘 捱 嗳 嗌 嫒 瑷 暧 砹 锿 霭
- set lpy=ai
- for /f "skip=2 delims=" %%A in (4处理.txt) do (
- set str=
- for /f "tokens=1*" %%B in ("%%A") do set py=%%B&set next=%%C
- for /f %%a in ("!next!") do set big=%%a
- echo !lit!~!big!:!input!
- for %%a in (!input! !G!) do (
- if %%a gtr !lit! (
- if %%a lss !big! (
- set str=!str! %%a
- set G=!G: %%a=!
- ) else echo G %%a&set G=!G: %%a=! %%a
- ) else echo L %%a&set /p=%%a <nul>>Lit.txt
- )
- echo>>9.txt !lpy! !str!
- echo @!str!@
- for /f %%B in ("!input!") do set lit=%%B
- set input=!next!
- set lpy=!py!
- echo;
- pause
- cls
- )
- pause
- ::重新排序,将位置超前的字符安置到相应的拼音下,而位置滞后的字符输出到 Lit.txt 准备进行手工处理,生成 9.txt
复制代码
- ::手工处理,将 Lit.txt 中的字符按其可能的拼音依次尝试,补全 9.txt 中缺失的内容。
复制代码
- @echo off&setlocal enabledelayedexpansion
- set A=吖
- for /f "skip=1 tokens=2" %%a in (9.txt) do (
- if !A! lss %%a (echo !A! lss %%a) else echo !A! gtr %%a!!!!!!!&echo !A! lss %%a>>10.txt
- set A=%%a
- pause
- )
- echo end
- ping /t localhost>nul
- ::修正拼音顺序,生成 10.txt,用于对 9.txt 纠错
复制代码
- @echo off&setlocal enabledelayedexpansion
- (for /f "tokens=1*" %%a in (9.txt) do (
- set str=%%b
- for /f %%c in ("%%b") do set last=%%c
- for %%c in (%%a) do (
- for %%d in (!str!) do (
- if %%d lss !last! (
- for %%e in (!last!) do (
- set str=!str:%%e %%d=%%d %%e!
- set last=%%e
- )
- ) else set last=%%d
- )
- )
- echo %%a !str!
- ))>11.txt
- pause
- ::修正行内汉字顺序为从小到大
复制代码
- @echo off
- (for /f "tokens=1,2" %%a in (11.txt) do set /p=%%b %%a )<nul>12.txt
- ::再手工加上 11.txt 中的最后一个汉字作为拼音 zuo 的上限。历经 11 关磨难,终于搞定,泪奔...
复制代码
作者: lllsoslll 时间: 2011-11-14 17:49
受启发写个批处理汉字转拼音,算法时间复杂度O(n),空间复杂度O(1);
本代码仅高人可见:
作者: CrLf 时间: 2011-11-14 18:50
本帖最后由 CrLf 于 2011-11-14 19:00 编辑
回复 3# lllsoslll
汗...看不到代码...空间复杂度和时间复杂度是什么呀?
作者: lllsoslll 时间: 2011-11-14 23:16
连同此贴收藏之;
http://bathome.net/viewthread.php?tid=12329
作者: CrLf 时间: 2011-11-14 23:34
刚才 zqz0012005 提出并且证明了此处的顺序依据的是系统语言设置:
一、控制面板>区域和语言选项>自定义此格式(自定义区域选项)>排序>拼音/比划
二、注册表>"HKUS\用户SID\Control Panel\International\"下的"LocaleName"键值,若为 zh-CN 则是汉语拼音顺序,zh-CN_stroke 则是汉字笔画顺序。
我验证后的测试结果果然和他的猜测相符,所以,if 字符比较的排序依据应该是与系统中所设语言的字符排序一致的,文件、文件夹等也是以此排序。
作者: hanyeguxing 时间: 2011-11-16 17:46
可以参考:sort的l参数的
/l locale
替代由系统默认区域设置(即在安装时选择的语言和“国家(地区)”)定义的字符排序顺序。
作者: HAT 时间: 2011-11-17 21:39
回复 4# CrLf
空间复杂度:内存占用情况
时间复杂度:程序运行时间的长短
作者: CrLf 时间: 2011-11-17 23:08
回复 8# HAT
原来如此...不过不知内存占用主要受什么影响呢?
作者: HAT 时间: 2011-11-17 23:24
回复 9# CrLf
比如:
定义很多大数组
open的文件不close
生成的对象不销毁
等等
作者: Demon 时间: 2012-8-13 16:13
if的排序规则即lstrcmp函数的排序规则(详见《批处理技术内幕:IF命令》),而lstrcmp函数的排序规则与当前线程的Locale有关。
作者: Demon 时间: 2012-8-15 16:20
写了一个验证排序的C程序
http://bbs.bathome.net/viewthread.php?tid=18542
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |