中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
« [1] [2] [3] »
作者:
标题: 统计文本文件的字符个数 上一主题 | 下一主题
pusofalse
银牌会员




积分 1604
发帖 646
注册 2008-4-13
状态 离线
『楼 主』:  统计文本文件的字符个数

@echo off&setlocal enabledelayedexpansion
set/a n=0,m=0,z=0,x=0
if not "%1"=="" (set file=%1) else set /p file=把要统计的文件拖到此处:
if not exist %file% echo 找不到文件&exit/b
echo 正在计算,请稍候。。。
for /f "tokens=*" %%a in ('findstr /n .* %file%') do (
    set str=%%a
    set str=!str:*:=!
    call :lp
)
set /a n=%n%+%x%+%z%
echo %file%中有%n%个字符,[Space]有%m%个。
pause&goto :eof


:lp
if defined str (
   set var=!str:~0,1!
    if not "!var!"=="" set /a n+=1
    if "!var!"=="!" set /a z+=1
    if "!var!"=="^^" set /a x+=1
    if "!var!"==" " set /a m+=1
   set str=!str:~1!
   goto lp
)

虽然对特殊字符稍微做了一点处理,但同样不适用于P。。。

2008-4-24 21:59
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
slore
铂金会员





积分 5212
发帖 2478
注册 2007-2-8
状态 离线
『第 2 楼』:  

VBS的len函数很好用嗬。

2008-4-24 22:28
查看资料  发短消息 网志   编辑帖子  回复  引用回复
slore
铂金会员





积分 5212
发帖 2478
注册 2007-2-8
状态 离线
『第 3 楼』:  

如果纯e文的话,直接看大小嗬。

2008-4-24 22:28
查看资料  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 4 楼』:  这种学习方法值得提倡:

别的不说,楼主举一返三的精神是可贵的,也是一条提高的捷径,加油!!!



批处理之家新域名:www.bathome.net
2008-4-24 22:42
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
pusofalse
银牌会员




积分 1604
发帖 646
注册 2008-4-13
状态 离线
『第 5 楼』:  

谢谢楼上几位。。。VBS不会用。。。只会用一个msgbox - -|||

2008-4-24 23:19
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 6 楼』:  为支持楼主也来一个:

特殊字符太难处理了,故没考虑:
@echo off&setlocal enabledelayedexpansion
set n=0&set m=0&set zk=0&set wk=0
for /f "delims=" %%i in (a.txt) do set str=%%i&call :lp %%str%%
echo 文本中有文字%n%个,文字空格%wk%个,字符%m%个,字符空格%zk%个
pause>nul&goto :eof
:lp
if defined str (
   set var=%str:~,1%
   if /i !var! gtr z (
      set /a n+=1
      ) else (
      if "!var!"==" " (
         set /a zk+=1
         ) else (
         if "!var!"==" " (
            set /a wk+=1
            ) else (
            set /a m+=1
         )
      )
   )
set str=%str:~1%&goto lp
)
[ Last edited by zw19750516 on 2008-4-25 at 01:37 AM ]



批处理之家新域名:www.bathome.net
2008-4-25 01:27
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
pusofalse
银牌会员




积分 1604
发帖 646
注册 2008-4-13
状态 离线
『第 7 楼』:  



  Quote:
Originally posted by zw19750516 at 2008-4-25 01:27 AM:
特殊字符太难处理了,故没考虑:
[code]@echo off&setlocal enabledelayedexpansion
set n=0&set m=0&set zk=0&set wk=0
for /f "delims=" %%i in (a.txt) do set s ...

测试N遍之后显示此时不应有do。。。
刚开始时还挺正常的。。。不知为何~

----------------------
汗~! 又可以了。。。- -|||

[ Last edited by pusofalse on 2008-4-25 at 02:32 AM ]

2008-4-25 02:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
bjsh
银牌会员





积分 2000
发帖 621
注册 2007-1-1
状态 离线
『第 8 楼』:  

这一段倒是 不怕特殊字符。。 它是打印出每一行的字符数, 并没有进行
整体统计。。
@echo off
for /f "delims=" %%a in ('findstr /n .* test.txt') do (
        set "var=%%a"
        setlocal enabledelayedexpansion
        set var=!var:*:=!
        call :Loop
        echo !n!
        endlocal
)
pause
goto :eof

:Loop
if defined var (
set /a n+=1
set var=!var:~1!
goto Loop
)
当然你也可以用下面这个进行 整体统计,
但是这个对稍大点的文件就会有问题。。
导致setlocal 递归层过大。。
@echo off
for /f "delims=" %%a in ('findstr /n .* test.txt') do (
        set "var=%%a"
        setlocal enabledelayedexpansion
        set var=!var:*:=!
        call :Loop
        setlocal disabledelayedexpansion
)
echo %n%
pause
goto :eof

:Loop
if defined var (
set /a n+=1
set var=!var:~1!
goto Loop
)
这里有命令行固有的缺陷

假如你想完完整整的(包括特殊字符)获取到, 那在set "var=%%a"
之前 一定不要打开 变量延迟, 不然!号和^会被吃掉。。

但这样也造成另一个问题:

假如这有最开始的一个环境变量表
|----------------------------------------------|
|                                              |
|                                              |
|                                              |
-------------------------------------------------

执行set "var=%%a"后变为:
假如var=1:abcd
|----------------------------------------------|
|                                              |
|           var=1:abcd                    |
|                                              |
-------------------------------------------------

当你执行 setlocal 时, 会产生一个新表, 实际上是copy调用setlocal的那张表,
但是以后对环境变量的修改只会作用于新表,当执行 endlocal 时,会恢复到原来
那张表。

执行setlocal 后产生新表
|----------------------------------------------|
|                                              |
|           var=1:abcd                   |
|                                              |
-------------------------------------------------
执行
set var=!var:*:=!
call :Loop
后这张新表变为:
|----------------------------------------------|
|                                              |
|           var=abcd                      |
|           n=4                             |
-------------------------------------------------

当执行endlocal时 环境变量的表 恢复到最初 即

|----------------------------------------------|
|                                              |
|           var=1:abcd                   |
|                                              |
-------------------------------------------------

可见 n 没有了。。
这也是为什么第一个代码 只统计每一行 而没有 统计全部的原因

因为每一次统计 时 执行 set /a n+=1
n的初始值都为零。

可能有人会有这样的疑问: 不执行endlocal行不行。。
答案是也行, 就比如第二段代码

但是要记住: 一定要在 set "var=%%a"之前关闭掉 变量延迟

这样会不断的递归产生 环境表。

对于小文件还尚可。。 文件行数稍大便会 导致setlocal递归层数过大


所谓cmd固有缺陷:

cmd中实际上没有真正变量的概念
而是以环境变量来模拟或者说是代替的

对于这种方式有个问题
因为 父shell 可以传递环境变量 给子shell
而 子shell 无法 改变父 shell中的环境变量

所以在setlocal后对原“变量”的修改 无法传递回来。。

除非 将其存入磁盘。。

================================

所以 更可行的方式 是 利用第一个代码, 将各行的字符数写入临时文件

最后再从 临时文件中 读取并计算和。。。

缺点自然就是 产生临时文件。

======================================
受10楼兄弟的启发, 下面这个代码即可统计 不必产生临时文件,
而且也 发现了 把变量传递回来的好办法。 很聪明的一个办法。。。

@echo off
for /f "delims=" %%a in ('findstr /n .* a.txt') do (
        set "var=%%a"
        call :list
)

echo.%total%
pause>nul
goto :eof

:list
setlocal enabledelayedexpansion
set /a n=0
set var=!var:*:=!
call :loop
endlocal&set /a total+=%n%
goto :eof

:loop
if defined var (
  set /a n+=1
  set var=!var:~1!
  goto loop
)
主要在两点。。
1) 让 set /a total+=n 脱离 循环的区域 但又被执行到
原因是为了避免 在for中 没执行前的命令行扫描 即将 n 替换掉
2)endlocal&&set /a total+=n
很聪明的做法  也是传递回来的根本原因所在
因为在一行。。。 所以 命令行 会对整体进行扫描
因为扫描时还没有执行endlocal, n 的值仍然存在, 而对其的替换恰发生在此时
扫描完毕后 真正执行时,endlocal 后 还原回原来的环境变量表, 但是
set /a total+=n 在扫描后 n 被替换为一个确定的值, 因此n的值通过total
被传递回原来的环境表量表

刚好利用了 扫描替换变量和执行的时间差。。

注意一定要在同一行,
endlocal
set /a total+=n
分开写, 第二行则永远是零了。。。


[ Last edited by bjsh on 2008-4-26 at 11:26 AM ]

2008-4-25 14:19
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
plp626
银牌会员

钻石会员


积分 2278
发帖 1020
注册 2007-11-19
状态 离线
『第 9 楼』:  

要想函数用的好,setlocal 必须掌握!



山外有山,人外有人;低调做人,努力做事。

进入网盘(各种工具)~~ 空间~~cmd学习
2008-4-25 14:38
查看资料  发短消息 网志   编辑帖子  回复  引用回复
26933062
银牌会员





积分 2268
发帖 879
注册 2006-12-19
状态 离线
『第 10 楼』:  

8 楼版主的代码稍作修改即可达到效果:
@echo off
set w=1
for /f "delims=" %%a in ('findstr /n .* a.txt') do set "var=%%a"&call :lis
echo.&echo 字符总数是 %u%
pause>nul
goto :eof
:lis
  setlocal enabledelayedexpansion
  set var=!var:*:=!
  if not defined var endlocal&set /a w+=1&goto :eof
  call :loop
  echo 第 !w! 行有 !n! 个字符
  endlocal&set /a u+=%n%,w+=1
goto :eof
:loop
if defined var (
  set /a n+=1
  set var=!var:~1!
  goto loop
)
goto :eof
[ Last edited by 26933062 on 2008-4-25 at 06:06 PM ]

   此帖被 +8 点积分     点击查看详情   
评分人:【 bjsh 分数: +8  时间:2008-4-25 22:07




致精致简!
2008-4-25 18:05
查看资料  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 11 楼』:  顶!!!

bjsh版主描述的太清楚了,确实特殊字符太难处理了,尤其是在字符截取和开启变量延迟时,这里还真是cmd的瓶颈啊。



批处理之家新域名:www.bathome.net
2008-4-25 21:41
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 12 楼』:  



  Quote:
Originally posted by 26933062 at 2008-4-25 18:05:
8 楼版主的代码稍作修改即可达到效果:
[code]
@echo off
set w=1
for /f "delims=" %%a in ('findstr /n .* a.txt') do set "var=%%a"&call :lis
echo.&echo 字 ...

这样就不能统计字符种类了,如有空格统计也不准确,看来只要有特殊字符存在,批处理将难以做到对文本字符的精确统计了。



批处理之家新域名:www.bathome.net
2008-4-25 21:44
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
pusofalse
银牌会员




积分 1604
发帖 646
注册 2008-4-13
状态 离线
『第 13 楼』:  以下代码转自lxmxn

@echo off&setlocal enabledelayedexpansion
set /p file=
for /f "delims=: tokens=1*" %%a in ('findstr  /n .* %file%') do (
   set n=&set str=%%b
   if not "!str!"=="" (
   for %%i in (!str!) do set /a n+=1
   echo/line:%%a      !n!个字符串。。。【!str!】
   ) else (
   echo/line:%%a      0个字符串。。。
)
)
pause>nul&cls&goto :eof

只要有特殊字符,字符串个数也会计算错误,难道没有好的方法了吗~

2008-4-25 21:55
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 14 楼』:  

暂时想不到啊,其实我一直在思考这个问题,也一直找不到好的解决方案。



批处理之家新域名:www.bathome.net
2008-4-25 21:58
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
bjsh
银牌会员





积分 2000
发帖 621
注册 2007-1-1
状态 离线
『第 15 楼』:  

10 楼的代码很聪明 真的很聪明!

2008-4-25 22:06
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
« [1] [2] [3] »
请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: