找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 28359|回复: 8

[文本处理] 批处理如何提取特定列的内容?

[复制链接]
发表于 2017-9-10 20:55:08 | 显示全部楼层 |阅读模式

如附件所示,我需要将带有DNI特性的行列内容提取出来,应该怎么做尼?我试过用DNI作为关键字去扫描行,但是文件中有的不在一行上,例如C31,就会漏掉。大家有没有什么好办法?谢啦~~
发表于 2017-9-11 11:52:24 | 显示全部楼层
这种文件格式 太不规范了。处理起来很麻烦。
 楼主| 发表于 2017-9-11 22:17:41 | 显示全部楼层
是啊,画图软件自动生成的器件列表,让我头疼了好久。怎么都for不出来
发表于 2017-9-12 11:41:11 | 显示全部楼层
软件名提供一下看看。
找一下设置能看看能不能CSV格式。CSV格式对程序比较友好。
发表于 2017-9-12 12:22:55 | 显示全部楼层
本帖最后由 523066680 于 2017-9-12 15:13 编辑

BOM单,以前公司自己生产PCB的时候也做过BOM单的资料提取,分类统计。
C是电容 R是电阻,都是贴片料的编号,六七年前的事情,好怀念……

Perl脚本
  1. use utf8;
  2. use Encode;
  3. use IO::Handle;
  4. use File::Slurp;
  5. STDOUT->autoflush(1);

  6. my $src = encode('gbk', "原始文本.txt");
  7. my @source = read_file( $src );
  8. my $idx = 0;

  9. #去掉抬头
  10. do { shift @source } until ( $source[0]=~/======/  );
  11. shift @source;

  12. my $flag = 0;
  13. while ( $idx <= $#source )
  14. {
  15.     ($DNI, $Material) = (substr($source[$idx], 9, 3), substr($source[$idx], 76, 20));
  16.     $Material=~s/\s//g;

  17.     if ( $DNI eq "DNI" )
  18.     {
  19.         print $Material,"\n";
  20.         $flag = 1;
  21.     }
  22.     else
  23.     {
  24.         if ( $DNI eq "   " and $flag == 1 and $Material ne "" )
  25.         {
  26.             print $Material,"\n";
  27.         }
  28.         else
  29.         {
  30.             $flag = 0;
  31.         }
  32.     }

  33.     $idx++;
  34. }
复制代码
发表于 2017-9-12 15:12:49 | 显示全部楼层
主要有C31这种行,不然直接 tokens=6, delims=空格就行了。
为了照顾这行的话,就只好按列宽把他们取出来自己拆分,然后判断上一次的DNI是否是[DNI],
是的话这段也截取出来。

另外,文本处理的话,还是建议不要用批处理了,同样的思路,代码量多,还有很多字符的限制,处理起来浪费时间,解决自己的问题,允许机器上装别的语言工具的话,
建议ruby,pyhon。有要求不能装其他的语言解释器的话,也建议使用VBS或JS,而不是批处理。

批处理的话,如下,如果使用ruby,估计也就20行左右(1/4的代码量,而且可读性还高)。
  1. @echo off&setlocal enabledelayedexpansion

  2. set n=2
  3. for /f "tokens=1,2,3,4,5,6 delims= " %%a in (src.txt) do (
  4.    set /a n+=1
  5.    if not "x%%f"=="x" ( if "x%%b"=="x===" (
  6.       call :headline "%%a" "%%b" "%%c" "%%d" "%%e" "%%f"
  7.       goto :end_head
  8.    ))
  9. )

  10. :end_head
  11. echo COLUMN_LEN:%id_len%, %type_len%, %num_len%, %name_len%, %qty_len%, %des_len%
  12. echo.

  13. set is_data_end=0
  14. for /f "skip=%n% delims=" %%a in (src.txt) do (
  15.    call :AnalysisLine "%%a"
  16.    if %is_data_end% NEQ 0 goto :end_data
  17. )

  18. :end_data
  19. pause
  20. goto :EOF

  21. :AnalysisLine
  22. set "AL_line=%~1"
  23. set AL_id=!AL_line:~0,%id_len%!
  24. set AL_type=!AL_line:~%type_start%,%type_len%!
  25. set AL_des=!AL_line:~%des_start%,%des_len%!

  26. if "x%AL_id%"=="x TOTAL" (
  27.   set is_data_end=1
  28.   goto :EOF
  29. )

  30. if "x%AL_type%"=="x   " (
  31.   set "AL_type=%AL_type_LAST%"
  32. )

  33. set AL_type_LAST=%AL_type%

  34. if "x%AL_type%"=="xDNI" (
  35.   echo [%AL_des%]
  36. )
  37. goto :EOF

  38. :headline
  39. call :Len %1
  40. set id_len=%Len_Ret%
  41. call :Len %2
  42. set /a type_start=%id_len%+3
  43. set type_len=%Len_Ret%
  44. call :Len %3
  45. set num_len=%Len_Ret%
  46. call :Len %4
  47. set name_len=%Len_Ret%
  48. call :Len %5
  49. set qty_len=%Len_Ret%
  50. call :Len %6
  51. set /a des_start=%id_len%+%type_len%+%num_len%+%name_len%+%qty_len%+5*3
  52. set des_len=%Len_Ret%
  53. goto :EOF


  54. :Len
  55.   set LenVar_i=0
  56.   set LenVar_Str=%~1
  57.   if "x%LenVar_Str%"=="x" (
  58.     set /a Len_Ret=0
  59.     goto :EOF
  60.   )
  61.   :Len_Loop
  62.     set LenVar_c=!LenVar_Str:~%LenVar_i%,1!
  63.     if "x%LenVar_c%"=="x" goto :Len_EndLoop
  64.     set /a LenVar_i+=1
  65.     goto :Len_Loop

  66.   :Len_EndLoop
  67.   set /a Len_Ret=LenVar_i
  68.   goto :EOF
复制代码

评分

参与人数 3PB +6 技术 +2 收起 理由
mmmike + 1 乐于助人
codegay + 1 1
523066680 + 6 乐于助人(最后你还是写了batch

查看全部评分

发表于 2017-9-12 15:17:46 | 显示全部楼层
写了个ruby版的,5分钟吧。18行,还有4,5行变量定义。
截取,获取长度直接有属性方法,用起来就是方便。
  1. lines = File.readlines('src.txt')
  2. dataline = false
  3. last_type = ''
  4. des_start = des_len = 0

  5. lines.each do |line|
  6.   line.chomp! # 去掉结尾Windows上可能多的\r回车符
  7.   if dataline == false && line[0, 6] == ' S.No.'
  8.     line =~ /^( S.No.   DNI   .+Qty   )(Ref Des +)   COMPANY/       #正则匹配 标题
  9.     des_start, des_len = $1.length, $2.length                       #保存Des的标题的开始和长度
  10.     dataline = true
  11.   elsif dataline == true
  12.     type = line[9, 3]    #DNI列固定?
  13.   end
  14.   break if line[0, 6] == ' TOTAL'     #遇到TOTAL结束
  15.   type = last_type if type == '   '   #如果type是3个空格,那么用上次type
  16.   last_type = type                    #设置当前type为最后type
  17.   puts "[#{line[des_start, des_len]}]" if type == 'DNI'
  18. end
复制代码

评分

参与人数 2技术 +2 收起 理由
mmmike + 1 乐于助人
codegay + 1 1

查看全部评分

发表于 2017-9-12 15:27:10 | 显示全部楼层
本帖最后由 523066680 于 2017-9-12 15:31 编辑

因为这个表有些信息位置是固定的,也没有中文之类的字符,批处理截取还算可以
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set "file=原始文本.txt"
  4. set /a flag = 0

  5. for /f "tokens=* delims=" %%a in ('type %file% ^| more +7 ') do (
  6.         set "str=%%a"
  7.         set DNI=!str:~9,3!
  8.         set Material=!str:~76,20!
  9.         set Material=!Material: =!
  10.         if "!DNI!" == "DNI" (
  11.                 echo !DNI! !Material!
  12.                 set /a flag = 1
  13.         ) else (
  14.                 if "!DNI!!flag!" == "   1" (
  15.                         if not "!Material!" == "" (
  16.                                 echo !DNI! !Material!
  17.                         )
  18.                 ) else (
  19.                         set /a flag=0
  20.                 )
  21.         )
  22. )
  23. pause
复制代码

评分

参与人数 1技术 +1 收起 理由
mmmike + 1 感谢给帖子标题标注[已解决]字样

查看全部评分

 楼主| 发表于 2017-9-12 21:26:07 | 显示全部楼层
感谢大家的热心的帮助;字符串截取太巧妙了!!!!!完全不需要考虑无用信息的干扰。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-19 22:12 , Processed in 0.023315 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表