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

[文本处理] 批处理中文分词的实现

虽然没多少人关注这个话题,但还是发个帖,开个头,希望有后来人。
       ——以下两段代码只能说是“实现了功能”,但效率很差。假如是自制的小字典还可以,使用大词库就非常吃力了。经测试,使用大词库,一句话可能要一两分钟才能切分词语!~
       ——分词好像是好多学校计算机专业的作业题哦,搜索过几篇分词的学生毕业论文,有些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. 通常,句子由字和词组成,分词就是将句子变回字和词。
  3. 如句子:
  4. 我喜欢音乐。
  5. 分词就是把句子中的词语用空格等方式分开,变成:
  6. 我 喜欢 音乐。
  7. 分词的目的是为了提取句子中的词语/关键词以便做搜索、摘要等等用途。
  8. 分词属于计算机自然语言处理的基础,是有难度的,如上例的切分结果可能有两种:
  9. 1、我 | 喜欢 | 音乐。
  10. 2、我 | 喜 | 欢音 | 乐。
  11. 要正确分词需要“消除歧义”。另外,还要“登陆新词”,也就是如新词、姓名等如何切分?
复制代码


测试题

  1. 以下是测试题,用以测试你分词的准确率:
  2. 我喜欢坐在面包车上一边吃面包一边看北京天安门门楼的门
  3. 我喜欢坐在面包车上一边吃面包一边看北京大学生活动中心门楼的门
  4. 我喜欢坐在面包车上一边吃面包一边看北京大学生活在音乐里
  5. 我喜欢坐在面包车上一边吃面包一边看北京大学生活很好
  6. 我喜欢坐在面包车上一边吃面包一边看北京大学的学生生活在音乐里
  7. 我喜欢坐在面包车上一边吃面包一边看北京大学的学生活在音乐里
  8. 广西大学生活很好
  9. 我喜欢吃鸭肉
  10. 我喜欢音乐
  11. 我喜欢吃面条
  12. 伟大学生生活
  13. 大学生活动
  14. 大学生活动中心
  15. 大学生活好
  16. 发展中国家庭养猪事业
  17. 你说的确实在理
  18. 中华人民共和国万岁
  19. 吃面包
复制代码

批处理中文分词之正向最大匹配法

  1. @ECHO OFF&SETLOCAL ENABLEDELAYEDEXPANSION
  2. :FJJZ
  3. CLS
  4. SET /P INF=    你对电脑说:
  5. ECHO.
  6. CD.>S.TXT
  7. FOR /L %%I IN (0,1,100) DO (
  8. 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
  9. REM 截取四个字组成的词语,如“刻舟求剑”————意味着缺陷:四个字以上的词语如“中华人民共和国”不在截取范围。
  10. 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
  11. REM 截取三个字组成的词语,如“批处理”————前面判断字符是否赋值,后面用于与词库匹配。
  12. 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
  13. REM 截取两个字组成的词语,如“胜利”————后面结果保留字符长度和偏移量。
  14. 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
  15. REM 截取一个字组成的词语,如“锅”。
  16. )>>S.TXT
  17. REM 以上代码很好地解释了字符串的截取和匹配,思路很清晰,但效率很差,原因在于每截取一个字词就匹配一下词库,FOR使用得太频繁。
  18. rem 一般我写代码都是,首先着重在于描述过程,达到目的后优化代码,提高效率。我是按人的思路写代码,不是按机器的思路写代码,所以效率差了。
  19. REM 改良的思路应该是,先将截取结果写入一个临时文件,然后使用“FINDSTR /I /X /G:TMP.TXT   DICTIONARY.TXT>>S3.TXT”与词库匹配,试了一下,效果明显提高。有空再改。
  20. SET VAR=-1
  21. ECHO 切分结果:
  22. ECHO.
  23. :LP
  24. SET /A VAR+=1
  25. FOR /F "TOKENS=1,2,3,*"   %%I IN (S.TXT) DO (
  26. IF !VAR!==%%J (
  27. SET /P K= 【%%K】<NUL
  28. REM ECHO %%K 1
  29. SET /A VAR=%%J+%%I
  30. )
  31. )
  32. IF %VAR% LSS 30 GOTO LP
  33. REM 上面这个比较简单,就是将切分出来的词语按照字符长度和偏移量重新组装句子,并用空格和【】隔开以突出词语。
  34. REM 前面有过一段时间为这几行字母折腾了好几天,后来想通了原来竟是这么简单。
  35. ECHO.
  36. ECHO.
  37. PAUSE
  38. GOTO FJJZ
复制代码

批处理中文分词之交集型词语匹配

(包含正向最大匹配)

  1. @echo off&setlocal enabledelayedexpansion
  2. :fjjz
  3. cls
  4. set /p inf=    输入句子:
  5. cd.>S.TXT
  6. for /l %%i in (0,1,100) do (
  7. set strdd=!inf:~%%i,4!&if defined strdd set strddo=!strdd:~3,1!&if defined strddo   for /f "tokens=1,*" %%a in
  8. (dictionary.txt) do if "%%a"=="!strdd!" echo 4 %%i %%a %%b      %%i,4
  9. set strcc=!inf:~%%i,3!&if defined strcc set strcco=!strdd:~2,1!&if defined strcco   for /f "tokens=1,*" %%e in
  10. (dictionary.txt) do if "%%e"=="!strcc!" echo 3 %%i %%e %%f      %%i,3
  11. set strbb=!inf:~%%i,2!&if defined strbb set strbbm=!strbb:~1,1!&if defined strbbm   for /f "tokens=1,*" %%x in
  12. (dictionary.txt) do if "%%x"=="!strbb!" echo 2 %%i %%x %%y      %%i,2
  13. set straa=!inf:~%%i,1!&if defined straa for /f "tokens=1,*" %%m in (dictionary.txt) do if "%%m"=="!straa!" echo 1 %%i %%m %
  14. %n       %%i,1
  15. )>>S.TXT
  16. cd.>zk1.txt
  17. set var=-1
  18. :lp
  19. set /a var+=1
  20. for /f "tokens=1,2,3,*"   %%i in (S.txt) do (
  21. if !var!==%%j (
  22. set /p k= %%k<nul
  23. set /a var=%%j+%%i
  24. )
  25. )>>zk1.txt
  26. if %var% lss 30 goto lp
  27. echo.
  28. cd.>zk2.txt
  29. for /f "tokens=1,2,3,*"   %%a in (S.txt) do if %%a==2 set /p s= %%c<nul>>zk2.txt
  30. set /p wj=<zk1.txt
  31. set /p wj1=<zk2.txt
  32. for    %%i in (!wj!) do (
  33. for    %%a in (!wj!) do (
  34. set dfa=%%i
  35. set ahe=!dfa:~2,1!
  36. for    %%e in (!wj1!) do (
  37. for    %%x in (!wj1!) do (
  38. if defined ahe if "%%i%%a"=="%%e%%x" set vdae=%%e&set vdaea=%%x&set vdbe=%%i&set vdbea=%%a
  39. )
  40. )
  41. )
  42. )
  43. echo.
  44. set /p lied=<zk1.txt
  45. for   %%i in (!lied!) do (
  46. if "%%i"=="!vdbe!" (echo !vdae! !vdaea!) else (if not "!vdaea:~1,1!"=="%%i" echo %%i)
  47. )
  48. echo.
  49. pause
  50. del zk1.txt,zk2.txt
  51. goto fjjz
复制代码

大文本处理,Perl脚本可能比较高效。
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

原帖由 Batcher 于 2010-9-14 19:05 发表
大文本处理,Perl脚本可能比较高效。

谢谢!~
我想学点其他处理大文本的技术,大大给点建议,如何?

TOP

=.= 那句话就是建议……

TOP

回复 3楼 的帖子

可以学习一下sed和gawk,大多时候比BAT高效。
Perl脚本一般来说更加高效,但缺点是需要安装一个环境才能执行,不像sed和gawk直接复制一下exe文件就行。
关键还是看自己对哪个方面更加感兴趣吧。
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

原帖由 Batcher 于 2010-9-14 20:49 发表
可以学习一下sed和gawk,大多时候比BAT高效。
Perl脚本一般来说更加高效,但缺点是需要安装一个环境才能执行,不像sed和gawk直接复制一下exe文件就行。
关键还是看自己对哪个方面更加感兴趣吧。

很好!谢谢!~
当时也想过用SED,但想想还是用纯P。因为SED没用过,需要重头去学。而当时我比较有想法了就先写P了,也是想从另外的角度试试看批处理是否能做这件事情,虽然我相信批处理能做,但结果效率太差了。
————————————————————————————————
感觉我的分词准确率比一些由C、java等的写的分词小程序要高——一次性通过一些公开的测试题目检测。但速度就不敢恭维了,我的一句话就用时一两分钟,人家的1万字才1秒,10000字以内的文章完全切分,用时间不超过1秒!——看来真的要改行才行,否则辜负了聪明!~

TOP

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

批处理作这个也许是真的存在效率问题,但也应该不至于这么慢吧,本想研究下你的代码,但看到了上面这一堆,就有种想吐的感觉,起码的分行和缩进都不会吗?你的代码不打算让别人看的吗?不知道你的 dictionary.txt 文件有多大,这样循环嵌套速度快才是怪事。有兴趣的话最好把意图用文字描述清楚,看看别人是否能写出比你效率高的代码来。。
技术问题请到论坛发帖求助!

TOP

批处理的效率虽然是比不上其它的XX,但是,也因为批处理的特点,往往是可以取巧的!!

下面的代码,实现词拆分查表功能,可以在一秒内完成:
注意:dictionary.txt 词库,需以较长的词在前,短在后的顺序排列
  1. @echo off&setlocal enabledelayedexpansion
  2. :lp
  3. set str=
  4. echo;
  5. echo;直接回车退出测试
  6. set /p str=输入一个字符串:
  7. if "!str!" equ "" goto :eof
  8. setlocal enabledelayedexpansion
  9. set/a z=8180,x=0&for /l %%a in (1,1,14) do (set/a "y=(z-x)/2+x"
  10.     for %%b in (!y!) do if "!str:~%%b,1!" equ "" (set/a z=y) else (set/a x=y)
  11. )
  12. ::计算输入串的长度
  13. ::sap 存入同等长度的空格串
  14. set sap=
  15. (for /l %%i in (0,1,!z!) do (
  16.     set "spa= !spa!"
  17.     set/a x=z-%%i
  18.     for /l %%j in (1,1,!x!) do (
  19.         echo;!str:~%%i,%%j!
  20.         set/a y=%%i+%%j
  21.         for %%a in ("!str:~%%i,%%j!") do (
  22.             set ##%%~a=%%i-!y!-%%j !##%%~a!
  23.         )
  24.     )
  25. ))>fen.tmp
  26. ::进行排列拆分到临时文件fen.tmp,同时取各分词的长度,及在原句中的起址位置,并按一定的规则保存
  27. set var=!str!
  28. for /f "tokens=*" %%a in ('findstr /x /i /g:fen.tmp dictionary.txt') do (
  29.   for %%k in (!##%%a!) do (
  30.     if "!var:%%a=!" neq "!var!" (
  31.       for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
  32.         if "!var:~%%b,1!" neq " " (
  33.           echo;截取过程:[!var!]  %%a
  34.           set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
  35.           set $$%%b=%%a
  36.         )
  37.       )
  38.     )
  39.   )
  40. )
  41. ::搜索词库,并做已经截取过记号,同时为恢复分词在原句中的位置做准备
  42. echo;
  43. if "!var: =!" neq "" (
  44.   echo;词库中没有的:
  45.   for %%a in (!var!) do (
  46.     for %%k in (!##%%a!) do (
  47.       if "!var:%%a=!" neq "!var!" (
  48.         for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
  49.           if "!var:~%%b,1!" neq " " (
  50.             echo;截取过程:[!var!]  %%a
  51.             set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
  52.             set $$%%b=%%a
  53.           )
  54.         )
  55.       )
  56.     )
  57.   )
  58. ) else (echo;所有字符均可在词库中到)
  59. ::对在词库中找不到的分词,也进行同样的处理
  60. echo;
  61. set dest=
  62. for /l %%a in (0,1,!z!) do set dest=!dest! !$$%%a!
  63. echo;最终拆分:!dest!
  64. endlocal&goto :lp
复制代码

[ 本帖最后由 netbenton 于 2010-9-15 03:32 编辑 ]

TOP

原帖由 随风 于 2010-9-15 01:17 发表

批处理作这个也许是真的存在效率问题,但也应该不至于这么慢吧,本想研究下你的代码,但看到了上面这一堆,就有种想吐的感觉,起码的分行和缩进都不会吗?你的代码不打算让别人看的吗?不知道你的 dictionary.txt  ...

       随风大哥,我解析一下你引用的代码,这四行用于截取输入的句子中的词语,第一个是截取四字词,如“肆无忌惮”,第二个是三字句,如“天安门”,第三个是二字词,如“北京”,第三个是一字词,如“门”。截取之后进行词语的匹配,就是将截取出来的词语查询词库,如果查询到就表示该成语成立,是一个多字词。在这里使用的是FOR,我知道FOR的效率不高,改用FINDSTR,但没改好。所以效率打折扣了,因时间关系,我希望大家帮忙优化,所以,你看到想吐是可以理解的。
       至于缩进,我知道看起来很美观,可是我很不适应,你如果知道每次我看到缩进的代码我都会取消缩进你就知道我多么讨厌缩进了,因为缩进仅仅是为了美观,有层次,但实际上对于一个懂得代码的人来说那毫无意义。而为了达到缩进而不停的敲击空格键更是浪费时间。我不反对缩进,但我本身是不习惯缩进的,请见谅。
       另外,我自己制作的词典很小,所以查询速度比较快,我下载的是去除拼音字母的标准词库213663词条.TXT,有1.60M,所以用四个FOR解析就有效率问题了。我知道有问题,因技术和时间的问题,现在无法优化,所以请大家帮忙……谢谢!~

[ 本帖最后由 cjiabing 于 2010-9-15 02:32 编辑 ]

TOP

原帖由 netbenton 于 2010-9-15 01:40 发表
批处理的效率虽然是比不上其它的XX,但是,也因为批处理的特点,往往是可以取巧的!!

下面的代码,实现词拆分查表功能,可以在一秒内完成:
注意:dictionary.txt 词库,需以较长的词在前,短在后的顺序排列@ec ...

谢谢netbenton兄的代码,有空慢慢研究,尝试了一下,似乎效果特别快,但不知道是否按既定要求执行,等我写完两篇论文在做答复,谢谢!~
______________________
netbenton兄,你把切分出来的词语做下处理,用空格隔开或者用其它标记标记一下,否则不知道你切分出来的词语在哪里!
代码很深奥,有空再慢慢研究,呵呵

[ 本帖最后由 cjiabing 于 2010-9-15 11:16 编辑 ]

TOP

回复 9楼 的帖子

可以尝试一下支持自动缩进的编辑器,比如:Notepad++
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

原帖由 Batcher 于 2010-9-15 09:21 发表
可以尝试一下支持自动缩进的编辑器,比如:Notepad++


       平时偶尔也用 notepad++ 啊,但没弄出8L的效果来。 notepad++ 看起来眼花缭乱的,怕不小心出错就不敢用,除非为了查找和替换。
       平常都是直接用系统的记事本,习惯了竖着看代码。虽然缩进很有诗歌的形式美,也希望那样做,可我不习惯,每次看人家缩进的代码,我非得取消缩进才好理解——矣,人贱没办法。

TOP

代码缩进绝非仅仅是为了好看,更主要的作用是便于理解代码。通过缩进,别人可以很容易看清你的代码结构,哪些块是干什么用的,哪些语句组成一个语句块。。。。。。。。
把语句盲目的用 &  符号连接起来,会使人很难看明白哪些语句可以拆开来看,哪些语句是一个块中的。。。。
技术问题请到论坛发帖求助!

TOP

8楼的代码,因为findstr 的一些特性,存在一些bug,修改如下:

一、词库搜索代码:
    findstr /x /g:fen.tmp /f:dics.txt

二、把词库按字数分别存放,并且文件名上可见词的字数。如:
[email=dict@1.txt]dict@1.txt[/email]
1人
1们
...

[email=dict@2.txt]dict@2.txt[/email]
2人民
2后门
...

......

些种办法把词分出来后,可方便词库的维护。
以下代码可把楼主提供的词库转换成按字数分文档存放。
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (0,1,10) do del dict@%%a.txt /q
  3. echo;%time%
  4. for /f "tokens=*" %%a in (dic16.txt) do (
  5.    set str=%%a
  6.    if "!str:~9!" equ "" (
  7.       set str=0123456789%%a
  8.       set n=!str:~-10,1!
  9.       echo;!n!%%a>>dict@!n!.txt
  10.    ) else (
  11.       echo;!n!%%a>>dict@10.txt
  12.    )
  13. )
  14. (for /f %%a in (dictionar@1.txt) do (echo;1%%a))>dict@1.txt
  15. dir /o-n /b dict@*>dics.txt
  16. echo;%time%
  17. pause
复制代码
三、dics.txt  存放各分词库的文件名,以字数长的分词库在前,短在后。
    dics.txt内容:
[email=dict@10.txt]dict@10.txt[/email]
[email=dict@9.txt]dict@9.txt[/email]
[email=dict@8.txt]dict@8.txt[/email]
[email=dict@7.txt]dict@7.txt[/email]
[email=dict@6.txt]dict@6.txt[/email]
[email=dict@5.txt]dict@5.txt[/email]
[email=dict@4.txt]dict@4.txt[/email]
[email=dict@3.txt]dict@3.txt[/email]
[email=dict@2.txt]dict@2.txt[/email]
[email=dict@1.txt]dict@1.txt[/email]

四、分词代码修改后,不再有搜索漏网的bug。并且对速度影响不大,20个字数长度的句子,拆分用时在一秒内。
  1. @echo off&setlocal enabledelayedexpansion
  2. :lp
  3. set str=
  4. echo;
  5. echo;直接回车退出测试
  6. set /p str=输入一个字符串:
  7. set ti=%time%
  8. if "!str!" equ "" goto :eof
  9. setlocal enabledelayedexpansion
  10. set/a z=8180,x=0&for /l %%a in (1,1,14) do (set/a "y=(z-x)/2+x"
  11.     for %%b in (!y!) do if "!str:~%%b,1!" equ "" (set/a z=y) else (set/a x=y)
  12. )
  13. ::计算输入串的长度
  14. ::sap 存入同等长度的空格串
  15. set lens=1 2 3 4 5 6 7 8 9 10 11
  16. set/a z1=z-1
  17. set sap=
  18. (for /l %%i in (0,1,!z1!) do (
  19.     set "spa= !spa!"
  20.     set one=!str:~%%i,1! !one!
  21.     set/a x=z-%%i
  22.     for %%j in (!lens!) do (
  23.         set/a y=%%i+%%j
  24.         echo;%%j!str:~%%i,%%j!
  25.         for %%a in ("!str:~%%i,%%j!") do (
  26.             set ##%%~a=%%i-!y!-%%j !##%%~a!
  27.         )
  28.     )
  29. ))>fen.tmp
  30. ::(for /l %%a in (0,1,!z!) do for %%k in (!@%%a!) do (echo;%%k))>fen.tmp
  31. ::进行排列拆分到临时文件fen.tmp,同时取各分词的长度,及在原句中的起址位置,并按一定的规则保存
  32. ::似乎要从短到长,findstr才能完全正确查找
  33. set var=!str!
  34. echo;!vvv!
  35. for /f "tokens=2* delims=:123456789" %%1 in ('findstr /x /g:fen.tmp /f:dics.txt') do (
  36.   for %%k in (!##%%2!) do (
  37.     if "!var:%%2=!" neq "!var!" (
  38.       for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
  39.         if "!var:~%%b,%%d!" equ "!str:~%%b,%%d!" (
  40.           echo;截取过程:[!var!]  %%2
  41.           set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
  42.           set $$%%b= [%%2]
  43.         )
  44.       )
  45.     )
  46.   )
  47. )
  48. ::搜索词库,并做已经截取过记号,同时为恢复分词在原句中的位置做准备
  49. echo;
  50. if "!var: =!" neq "" (
  51.   echo;词库中没有的:
  52.   for %%a in (!var!) do (
  53.     for %%k in (!##%%a!) do (
  54.       if "!var:%%a=!" neq "!var!" (
  55.         for /f "tokens=1,2,3 delims=-" %%b in ("%%k") do (
  56.           if "!var:~%%b,1!" neq " " (
  57.             echo;截取过程:[!var!]  %%a
  58.             set var=!var:~0,%%b!!spa:~,%%d!!var:~%%c!
  59.             set $$%%b= %%a
  60.           )
  61.         )
  62.       )
  63.     )
  64.   )
  65. ) else (echo;所有字符均可在词库中找到)
  66. ::对在词库中找不到的分词,也进行同样的处理
  67. echo;
  68. set dest=
  69. for /l %%a in (0,1,!z!) do set dest=!dest!!$$%%a!
  70. echo;最终拆分:!dest!
  71. echo;%ti%
  72. echo;%time%
  73. endlocal&goto :lp
复制代码
五、词在库中的先后,决定了匹配的优先顺序,只要改变词在库中的顺序,即可改变折分的准确性。

我另外写了一个词库维护的代码,可以改变词在库中的顺序,增加词到词库中。

初版只支持一次修改两个词顺序。代码如下:
  1. @echo off&setlocal enabledelayedexpansion
  2. echo;  ** 调整词序/增加词组 **
  3. set /p str1=输入第一字符串:
  4. set /p str2=输入第二字符串:
  5. if "!str1!" equ "!str2!" goto :eof
  6. set str=0123456789!str1!
  7. set n1=!str:~-10,1!
  8. set str=0123456789!str2!
  9. set n2=!str:~-10,1!
  10. set str1=!n1!!str1!
  11. set str2=!n2!!str2!
  12. if "!n1!" equ "!n2!" (
  13.   findstr /x "!str1!" dict@!n1!.txt>nul
  14.   if !errorlevel! equ 1 (
  15.         set str1=%str2%
  16.         set str2=%str1%
  17.         set xchg=y
  18.      findstr /x "!str1!" dict@!n1!.txt>nul
  19.      if !errorlevel! equ 1 set xchg=n
  20.   )
  21.   if "!xchg!" neq "n" (
  22.     copy dict@!n1!.txt fen.tmp /y
  23.     (for /f %%a in (fen.tmp) do (
  24.         if "%%a" neq "!str2!" echo;%%a
  25.         if "%%a" equ "!str1!" (
  26.           echo;!str2!
  27.           if defined xchg (echo;!str1!)
  28.         )
  29.     ))>dict@!n1!.txt
  30.     echo;修改 [!str1!] 和 [!str2!] 在dict@!n1!.txt中的顺序
  31.   ) else (
  32.     echo;!str2!>>dict@!n1!.txt
  33.     echo;!str1!>>dict@!n1!.txt
  34.     echo;添加 [!str1!] 和 [!str2!] 到 dict@!n1!.txt
  35.   )
  36. ) else (
  37.   findstr /x "!str1!" dict@!n1!.txt>nul
  38.   if !errorlevel! equ 1 (
  39.     echo;!str1!>>dict@!n1!.txt
  40.     echo;添加 [!str1!] 到 dict@!n1!.txt
  41.   )
  42.   findstr /x "!str2!" dict@!n2!.txt>nul
  43.   if !errorlevel! equ 1 (
  44.      echo;!str2!>>dict@!n2!.txt
  45.      echo;添加 [!str2!] 到 dict@!n2!.txt
  46.   )
  47. )
  48. pause
复制代码
拆分句子示例:

输入一个字符串:这也是造成肇事车辆屡屡逃逸的一个主要原因

截取过程:[这也是造成肇事车辆屡屡逃逸的一个主要原因]  主要原因
截取过程:[这也是造成肇事车辆屡屡逃逸的一个           ]  屡屡
截取过程:[这也是造成肇事车辆  逃逸的一个           ]  车辆
截取过程:[这也是造成肇事    逃逸的一个           ]  逃逸
截取过程:[这也是造成肇事      的一个           ]  一个
截取过程:[这也是造成肇事      的             ]  也是
截取过程:[这  造成肇事      的             ]  造成
截取过程:[这    肇事      的             ]  肇事
截取过程:[这            的             ]  这
截取过程:[             的             ]  的
所有字符均可在词库中找到
最终拆分: [这] [也是] [造成] [肇事] [车辆] [屡屡] [逃逸] [的] [一个] [主要原因]
开始: 6:44:02.45
结束: 6:44:03.20

楼主出的测试例子结果如下(词库的一些词经过顺序调整):
最终拆分: [我] [喜欢] [坐在] [面包车] [上] [一边] [吃] [面包] [一边] [看] [北京] [天安门] [门楼] [的] [门]
最终拆分: [我] [喜欢] [坐在] [面包车] [上] [一边] [吃] [面包] [一边] [看] [北京] [大学生活动中心] [门楼] [的] [门]
最终拆分: [我] [喜欢] [坐在] [面包车] [上] [一边] [吃] [面包] [一边] [看] [北京大学] [生活] [在] [音乐] [里]
最终拆分: [我] [喜欢] [坐在] [面包车] [上] [一边] [吃] [面包] [一边] [看] [北京大学] [生活] [很好]
最终拆分: [我] [喜欢] [坐在] [面包车] [上] [一边] [吃] [面包] [一边] [看] [北京大学] [的] [学生] [生活] [在] [音乐] [里]
最终拆分: [我] [喜欢] [坐在] [面包车] [上] [一边] [吃] [面包] [一边] [看] [北京大学] [的] [学生] [活在] [音乐] [里]
最终拆分: [广西] [大学生活] [很好]
最终拆分: [我] [喜欢] [吃] [鸭肉]
最终拆分: [伟] [大学生] [生活]
最终拆分: [大学生活] [动]
最终拆分: [大学生活] [好]
最终拆分: [大学生活动中心]
最终拆分: [发展] [中国家庭养猪] [事业]
最终拆分: [你说] [的] [确实在] [理]

[ 本帖最后由 netbenton 于 2010-9-17 07:31 编辑 ]

TOP

经过几次测试实验,我认为,只要对词库进行一定的“驯化”,即调整顺序、合理的增/减词汇,应该可以正确拆分所有的句子。

这种分文档存放词库方法较为灵活,可以随意调整词的优先顺序。
比如:
在最长分词库前增加一个人名库,这样就可以,以最优先权去匹配人的名字。
把dics.txt  的内容改为:
name.txt
[email]dict@10.txt[/email]
[email]dict@9.txt[/email]
[email]dict@8.txt[/email]
[email]dict@7.txt[/email]
[email]dict@6.txt[/email]
[email]dict@5.txt[/email]
[email]dict@4.txt[/email]
[email]dict@3.txt[/email]
[email]dict@2.txt[/email]
[email]dict@1.txt[/email]

然后在name.txt里面存放人名/地名等:
3刘德华
3张曼玉
4比尔盖茨
5东方不败
2香港
2桂林

这样,name.txt 中的词即得到最优先权的匹配

TOP

返回列表