虽然没多少人关注这个话题,但还是发个帖,开个头,希望有后来人。
——以下两段代码只能说是“实现了功能”,但效率很差。假如是自制的小字典还可以,使用大词库就非常吃力了。经测试,使用大词库,一句话可能要一两分钟才能切分词语!~
——分词好像是好多学校计算机专业的作业题哦,搜索过几篇分词的学生毕业论文,有些IT大企业面试题……
——这个帖子重点讨论使用批处理进行中文分词的可能性,欢迎你参与……
以下是相关帖:
http://www.bathome.net/thread-9183-1-1.html
词库下载:
http://cjiabing.qupan.com/6627766.html
中文分词介绍:
http://baike.baidu.com/view/19109.htm
文章介绍:
http://hi.baidu.com/cjiabing/blog/item/4c95b91bf3abaa178718bff4.html
中文分词规范:
http://wenku.baidu.com/view/1dbd3fc58bd63186bcebbc7d.html
分词介绍
复制代码
- 分词,简单地说,就是将一句话拆解/切分成独立的词语。
- 通常,句子由字和词组成,分词就是将句子变回字和词。
- 如句子:
- 我喜欢音乐。
- 分词就是把句子中的词语用空格等方式分开,变成:
- 我 喜欢 音乐。
- 分词的目的是为了提取句子中的词语/关键词以便做搜索、摘要等等用途。
- 分词属于计算机自然语言处理的基础,是有难度的,如上例的切分结果可能有两种:
- 1、我 | 喜欢 | 音乐。
- 2、我 | 喜 | 欢音 | 乐。
- 要正确分词需要“消除歧义”。另外,还要“登陆新词”,也就是如新词、姓名等如何切分?
测试题
复制代码
- 以下是测试题,用以测试你分词的准确率:
- 我喜欢坐在面包车上一边吃面包一边看北京天安门门楼的门
- 我喜欢坐在面包车上一边吃面包一边看北京大学生活动中心门楼的门
- 我喜欢坐在面包车上一边吃面包一边看北京大学生活在音乐里
- 我喜欢坐在面包车上一边吃面包一边看北京大学生活很好
- 我喜欢坐在面包车上一边吃面包一边看北京大学的学生生活在音乐里
- 我喜欢坐在面包车上一边吃面包一边看北京大学的学生活在音乐里
- 广西大学生活很好
- 我喜欢吃鸭肉
- 我喜欢音乐
- 我喜欢吃面条
- 伟大学生生活
- 大学生活动
- 大学生活动中心
- 大学生活好
- 发展中国家庭养猪事业
- 你说的确实在理
- 中华人民共和国万岁
- 吃面包
批处理中文分词之正向最大匹配法
复制代码
- @ECHO OFF&SETLOCAL ENABLEDELAYEDEXPANSION
- :FJJZ
- CLS
- SET /P INF= 你对电脑说:
- ECHO.
- CD.>S.TXT
- FOR /L %%I IN (0,1,100) DO (
- SET STRDD=!INF:~%%I,4!&IF DEFINED STRDD SET STRDDO=!STRDD:~3,1!&IF DEFINED STRDDO FOR /F "TOKENS=1,*" %%A IN (DICTIONARY.TXT) DO IF "%%A"=="!STRDD!" ECHO 4 %%I %%A %%B %%I,4
- REM 截取四个字组成的词语,如“刻舟求剑”————意味着缺陷:四个字以上的词语如“中华人民共和国”不在截取范围。
- SET STRCC=!INF:~%%I,3!&IF DEFINED STRCC SET STRCCO=!STRDD:~2,1!&IF DEFINED STRCCO FOR /F "TOKENS=1,*" %%E IN (DICTIONARY.TXT) DO IF "%%E"=="!STRCC!" ECHO 3 %%I %%E %%F %%I,3
- REM 截取三个字组成的词语,如“批处理”————前面判断字符是否赋值,后面用于与词库匹配。
- SET STRBB=!INF:~%%I,2!&IF DEFINED STRBB SET STRBBM=!STRBB:~1,1!&IF DEFINED STRBBM FOR /F "TOKENS=1,*" %%X IN (DICTIONARY.TXT) DO IF "%%X"=="!STRBB!" ECHO 2 %%I %%X %%Y %%I,2
- REM 截取两个字组成的词语,如“胜利”————后面结果保留字符长度和偏移量。
- SET STRAA=!INF:~%%I,1!&IF DEFINED STRAA FOR /F "TOKENS=1,*" %%M IN (DICTIONARY.TXT) DO IF "%%M"=="!STRAA!" ECHO 1 %%I %%M %%N %%I,1
- REM 截取一个字组成的词语,如“锅”。
- )>>S.TXT
- REM 以上代码很好地解释了字符串的截取和匹配,思路很清晰,但效率很差,原因在于每截取一个字词就匹配一下词库,FOR使用得太频繁。
- rem 一般我写代码都是,首先着重在于描述过程,达到目的后优化代码,提高效率。我是按人的思路写代码,不是按机器的思路写代码,所以效率差了。
- REM 改良的思路应该是,先将截取结果写入一个临时文件,然后使用“FINDSTR /I /X /G:TMP.TXT DICTIONARY.TXT>>S3.TXT”与词库匹配,试了一下,效果明显提高。有空再改。
- SET VAR=-1
- ECHO 切分结果:
- ECHO.
- :LP
- SET /A VAR+=1
- FOR /F "TOKENS=1,2,3,*" %%I IN (S.TXT) DO (
- IF !VAR!==%%J (
- SET /P K= 【%%K】<NUL
- REM ECHO %%K 1
- SET /A VAR=%%J+%%I
- )
- )
- IF %VAR% LSS 30 GOTO LP
- REM 上面这个比较简单,就是将切分出来的词语按照字符长度和偏移量重新组装句子,并用空格和【】隔开以突出词语。
- REM 前面有过一段时间为这几行字母折腾了好几天,后来想通了原来竟是这么简单。
- ECHO.
- ECHO.
- PAUSE
- GOTO FJJZ
批处理中文分词之交集型词语匹配
(包含正向最大匹配)
复制代码
- @echo off&setlocal enabledelayedexpansion
- :fjjz
- cls
- set /p inf= 输入句子:
- cd.>S.TXT
- for /l %%i in (0,1,100) do (
- set strdd=!inf:~%%i,4!&if defined strdd set strddo=!strdd:~3,1!&if defined strddo for /f "tokens=1,*" %%a in
- (dictionary.txt) do if "%%a"=="!strdd!" echo 4 %%i %%a %%b %%i,4
- set strcc=!inf:~%%i,3!&if defined strcc set strcco=!strdd:~2,1!&if defined strcco for /f "tokens=1,*" %%e in
- (dictionary.txt) do if "%%e"=="!strcc!" echo 3 %%i %%e %%f %%i,3
- set strbb=!inf:~%%i,2!&if defined strbb set strbbm=!strbb:~1,1!&if defined strbbm for /f "tokens=1,*" %%x in
- (dictionary.txt) do if "%%x"=="!strbb!" echo 2 %%i %%x %%y %%i,2
- set straa=!inf:~%%i,1!&if defined straa for /f "tokens=1,*" %%m in (dictionary.txt) do if "%%m"=="!straa!" echo 1 %%i %%m %
- %n %%i,1
- )>>S.TXT
- cd.>zk1.txt
- set var=-1
- :lp
- set /a var+=1
- for /f "tokens=1,2,3,*" %%i in (S.txt) do (
- if !var!==%%j (
- set /p k= %%k<nul
- set /a var=%%j+%%i
- )
- )>>zk1.txt
- if %var% lss 30 goto lp
- echo.
- cd.>zk2.txt
- for /f "tokens=1,2,3,*" %%a in (S.txt) do if %%a==2 set /p s= %%c<nul>>zk2.txt
- set /p wj=<zk1.txt
- set /p wj1=<zk2.txt
- for %%i in (!wj!) do (
- for %%a in (!wj!) do (
- set dfa=%%i
- set ahe=!dfa:~2,1!
- for %%e in (!wj1!) do (
- for %%x in (!wj1!) do (
- if defined ahe if "%%i%%a"=="%%e%%x" set vdae=%%e&set vdaea=%%x&set vdbe=%%i&set vdbea=%%a
- )
- )
- )
- )
- echo.
- set /p lied=<zk1.txt
- for %%i in (!lied!) do (
- if "%%i"=="!vdbe!" (echo !vdae! !vdaea!) else (if not "!vdaea:~1,1!"=="%%i" echo %%i)
- )
- echo.
- pause
- del zk1.txt,zk2.txt
- goto fjjz
原帖由 Batcher 于 2010-9-14 20:49 发表
可以学习一下sed和gawk,大多时候比BAT高效。
Perl脚本一般来说更加高效,但缺点是需要安装一个环境才能执行,不像sed和gawk直接复制一下exe文件就行。
关键还是看自己对哪个方面更加感兴趣吧。
for /l %%i in (0,1,100) do (
set strdd=!inf:~%%i,4!&if defined strdd set strddo=!strdd:~3,1!&if defined strddo for /f "tokens=1,*" %%a in (dictionary.txt) do if "%%a"=="!strdd!" echo 4 %%i %%a %%b %%i,4
set strcc=!inf:~%%i,3!&if defined strcc set strcco=!strdd:~2,1!&if defined strcco for /f "tokens=1,*" %%e in (dictionary.txt) do if "%%e"=="!strcc!" echo 3 %%i %%e %%f %%i,3
set strbb=!inf:~%%i,2!&if defined strbb set strbbm=!strbb:~1,1!&if defined strbbm for /f "tokens=1,*" %%x in (dictionary.txt) do if "%%x"=="!strbb!" echo 2 %%i %%x %%y %%i,2
set straa=!inf:~%%i,1!&if defined straa for /f "tokens=1,*" %%m in (dictionary.txt) do if "%%m"=="!straa!" echo 1 %%i %%m %%n %%i,1
)>>S.TXT
复制代码
- @echo off&setlocal enabledelayedexpansion
- :lp
- set str=
- echo;
- echo;直接回车退出测试
- set /p str=输入一个字符串:
- if "!str!" equ "" goto :eof
- setlocal enabledelayedexpansion
- set/a z=8180,x=0&for /l %%a in (1,1,14) do (set/a "y=(z-x)/2+x"
- for %%b in (!y!) do if "!str:~%%b,1!" equ "" (set/a z=y) else (set/a x=y)
- )
- ::计算输入串的长度
- ::sap 存入同等长度的空格串
- set sap=
- (for /l %%i in (0,1,!z!) do (
- set "spa= !spa!"
- set/a x=z-%%i
- for /l %%j in (1,1,!x!) do (
- echo;!str:~%%i,%%j!
- set/a y=%%i+%%j
- for %%a in ("!str:~%%i,%%j!") do (
- set ##%%~a=%%i-!y!-%%j !##%%~a!
- )
- )
- ))>fen.tmp
- ::进行排列拆分到临时文件fen.tmp,同时取各分词的长度,及在原句中的起址位置,并按一定的规则保存
- set var=!str!
- for /f "tokens=*" %%a in ('findstr /x /i /g:fen.tmp dictionary.txt') do (
- for %%k in (!##%%a!) do (
- if "!var:%%a=!" neq "!var!" (
- for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
- if "!var:~%%b,1!" neq " " (
- echo;截取过程:[!var!] %%a
- set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
- set $$%%b=%%a
- )
- )
- )
- )
- )
- ::搜索词库,并做已经截取过记号,同时为恢复分词在原句中的位置做准备
- echo;
- if "!var: =!" neq "" (
- echo;词库中没有的:
- for %%a in (!var!) do (
- for %%k in (!##%%a!) do (
- if "!var:%%a=!" neq "!var!" (
- for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
- if "!var:~%%b,1!" neq " " (
- echo;截取过程:[!var!] %%a
- set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
- set $$%%b=%%a
- )
- )
- )
- )
- )
- ) else (echo;所有字符均可在词库中到)
- ::对在词库中找不到的分词,也进行同样的处理
- echo;
- set dest=
- for /l %%a in (0,1,!z!) do set dest=!dest! !$$%%a!
- echo;最终拆分:!dest!
- endlocal&goto :lp
原帖由 随风 于 2010-9-15 01:17 发表
批处理作这个也许是真的存在效率问题,但也应该不至于这么慢吧,本想研究下你的代码,但看到了上面这一堆,就有种想吐的感觉,起码的分行和缩进都不会吗?你的代码不打算让别人看的吗?不知道你的 dictionary.txt ...
原帖由 netbenton 于 2010-9-15 01:40 发表
批处理的效率虽然是比不上其它的XX,但是,也因为批处理的特点,往往是可以取巧的!!
下面的代码,实现词拆分查表功能,可以在一秒内完成:
注意:dictionary.txt 词库,需以较长的词在前,短在后的顺序排列@ec ...
三、dics.txt 存放各分词库的文件名,以字数长的分词库在前,短在后。复制代码
- @echo off&setlocal enabledelayedexpansion
- for /l %%a in (0,1,10) do del dict@%%a.txt /q
- echo;%time%
- for /f "tokens=*" %%a in (dic16.txt) do (
- set str=%%a
- if "!str:~9!" equ "" (
- set str=0123456789%%a
- set n=!str:~-10,1!
- echo;!n!%%a>>dict@!n!.txt
- ) else (
- echo;!n!%%a>>dict@10.txt
- )
- )
- (for /f %%a in (dictionar@1.txt) do (echo;1%%a))>dict@1.txt
- dir /o-n /b dict@*>dics.txt
- echo;%time%
- pause
五、词在库中的先后,决定了匹配的优先顺序,只要改变词在库中的顺序,即可改变折分的准确性。复制代码
- @echo off&setlocal enabledelayedexpansion
- :lp
- set str=
- echo;
- echo;直接回车退出测试
- set /p str=输入一个字符串:
- set ti=%time%
- if "!str!" equ "" goto :eof
- setlocal enabledelayedexpansion
- set/a z=8180,x=0&for /l %%a in (1,1,14) do (set/a "y=(z-x)/2+x"
- for %%b in (!y!) do if "!str:~%%b,1!" equ "" (set/a z=y) else (set/a x=y)
- )
- ::计算输入串的长度
- ::sap 存入同等长度的空格串
- set lens=1 2 3 4 5 6 7 8 9 10 11
- set/a z1=z-1
- set sap=
- (for /l %%i in (0,1,!z1!) do (
- set "spa= !spa!"
- set one=!str:~%%i,1! !one!
- set/a x=z-%%i
- for %%j in (!lens!) do (
- set/a y=%%i+%%j
- echo;%%j!str:~%%i,%%j!
- for %%a in ("!str:~%%i,%%j!") do (
- set ##%%~a=%%i-!y!-%%j !##%%~a!
- )
- )
- ))>fen.tmp
- ::(for /l %%a in (0,1,!z!) do for %%k in (!@%%a!) do (echo;%%k))>fen.tmp
- ::进行排列拆分到临时文件fen.tmp,同时取各分词的长度,及在原句中的起址位置,并按一定的规则保存
- ::似乎要从短到长,findstr才能完全正确查找
- set var=!str!
- echo;!vvv!
- for /f "tokens=2* delims=:123456789" %%1 in ('findstr /x /g:fen.tmp /f:dics.txt') do (
- for %%k in (!##%%2!) do (
- if "!var:%%2=!" neq "!var!" (
- for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
- if "!var:~%%b,%%d!" equ "!str:~%%b,%%d!" (
- echo;截取过程:[!var!] %%2
- set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
- set $$%%b= [%%2]
- )
- )
- )
- )
- )
- ::搜索词库,并做已经截取过记号,同时为恢复分词在原句中的位置做准备
- echo;
- if "!var: =!" neq "" (
- echo;词库中没有的:
- for %%a in (!var!) do (
- for %%k in (!##%%a!) do (
- if "!var:%%a=!" neq "!var!" (
- for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
- if "!var:~%%b,1!" neq " " (
- echo;截取过程:[!var!] %%a
- set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
- set $$%%b= %%a
- )
- )
- )
- )
- )
- ) else (echo;所有字符均可在词库中找到)
- ::对在词库中找不到的分词,也进行同样的处理
- echo;
- set dest=
- for /l %%a in (0,1,!z!) do set dest=!dest!!$$%%a!
- echo;最终拆分:!dest!
- echo;%ti%
- echo;%time%
- endlocal&goto :lp
拆分句子示例:复制代码
- @echo off&setlocal enabledelayedexpansion
- echo; ** 调整词序/增加词组 **
- set /p str1=输入第一字符串:
- set /p str2=输入第二字符串:
- if "!str1!" equ "!str2!" goto :eof
- set str=0123456789!str1!
- set n1=!str:~-10,1!
- set str=0123456789!str2!
- set n2=!str:~-10,1!
- set str1=!n1!!str1!
- set str2=!n2!!str2!
- if "!n1!" equ "!n2!" (
- findstr /x "!str1!" dict@!n1!.txt>nul
- if !errorlevel! equ 1 (
- set str1=%str2%
- set str2=%str1%
- set xchg=y
- findstr /x "!str1!" dict@!n1!.txt>nul
- if !errorlevel! equ 1 set xchg=n
- )
- if "!xchg!" neq "n" (
- copy dict@!n1!.txt fen.tmp /y
- (for /f %%a in (fen.tmp) do (
- if "%%a" neq "!str2!" echo;%%a
- if "%%a" equ "!str1!" (
- echo;!str2!
- if defined xchg (echo;!str1!)
- )
- ))>dict@!n1!.txt
- echo;修改 [!str1!] 和 [!str2!] 在dict@!n1!.txt中的顺序
- ) else (
- echo;!str2!>>dict@!n1!.txt
- echo;!str1!>>dict@!n1!.txt
- echo;添加 [!str1!] 和 [!str2!] 到 dict@!n1!.txt
- )
- ) else (
- findstr /x "!str1!" dict@!n1!.txt>nul
- if !errorlevel! equ 1 (
- echo;!str1!>>dict@!n1!.txt
- echo;添加 [!str1!] 到 dict@!n1!.txt
- )
- findstr /x "!str2!" dict@!n2!.txt>nul
- if !errorlevel! equ 1 (
- echo;!str2!>>dict@!n2!.txt
- echo;添加 [!str2!] 到 dict@!n2!.txt
- )
- )
- pause
华为二十四口交换机
原帖由 netbenton 于 2010-9-17 12:43 发表
可以吧~~~,结果如下:
输入一个字符串:华为二十四口交换机
截取过程:[华为二十四口交换机] 二十四
截取过程:[华为 口交换机] 交换机
截取过程:[华为 口 ] 华为
截取过程:[ 口 ] 口
...
原帖由 netbenton 于 2010-9-17 12:56 发表
输入一个字符串:华为二十四口交不好
截取过程:[华为二十四口交不好] 二十四
截取过程:[华为 口交不好] 不好
截取过程:[华为 口交 ] 华为
截取过程:[ 口交 ] 口交
所有字符均可在词库中找 ...
欢迎光临 批处理之家 (http://bathome.net./) | Powered by Discuz! 7.2 |