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

下面的代码,实现词拆分查表功能,可以在一秒内完成:
注意:dictionary.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 :lpCOPY

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

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后门
...

......

些种办法把词分出来后,可方便词库的维护。
以下代码可把楼主提供的词库转换成按字数分文档存放。
@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%
pauseCOPY
三、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个字数长度的句子,拆分用时在一秒内。
@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 :lpCOPY
五、词在库中的先后,决定了匹配的优先顺序,只要改变词在库中的顺序,即可改变折分的准确性。

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

初版只支持一次修改两个词顺序。代码如下:
@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
  )
)
pauseCOPY
拆分句子示例:

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

截取过程:[这也是造成肇事车辆屡屡逃逸的一个主要原因]  主要原因
截取过程:[这也是造成肇事车辆屡屡逃逸的一个           ]  屡屡
截取过程:[这也是造成肇事车辆  逃逸的一个           ]  车辆
截取过程:[这也是造成肇事    逃逸的一个           ]  逃逸
截取过程:[这也是造成肇事      的一个           ]  一个
截取过程:[这也是造成肇事      的             ]  也是
截取过程:[这  造成肇事      的             ]  造成
截取过程:[这    肇事      的             ]  肇事
截取过程:[这            的             ]  这
截取过程:[             的             ]  的
所有字符均可在词库中找到
最终拆分: [这] [也是] [造成] [肇事] [车辆] [屡屡] [逃逸] [的] [一个] [主要原因]
开始: 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

可以吧~~~,结果如下:

输入一个字符串:华为二十四口交换机

截取过程:[华为二十四口交换机]  二十四
截取过程:[华为   口交换机]  交换机
截取过程:[华为   口   ]  华为
截取过程:[     口   ]  口

所有字符均可在词库中找到

最终拆分: [华为] [二十四] [口] [交换机]
12:36:47.53
12:36:47.98


输入一个字符串:华为24口交换机
截取过程:[华为24口交换机]  交换机
截取过程:[华为24口   ]  华为
截取过程:[  24口   ]  口
词库中没有的:
截取过程:[  24    ]  24
最终拆分: [华为] 24 [口] [交换机]
12:45:33.93
12:45:34.34

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

TOP

输入一个字符串:华为二十四口交不好

截取过程:[华为二十四口交不好]  二十四
截取过程:[华为   口交不好]  不好
截取过程:[华为   口交  ]  华为
截取过程:[     口交  ]  口交

所有字符均可在词库中找到

最终拆分: [华为] [二十四] [口交] [不好]
12:55:39.01
12:55:39.48

库里有那个词的,只是没有匹配到它

TOP

返回列表