Board logo

标题: [文本处理] 批处理如何提取特定列的内容? [打印本页]

作者: mmmike    时间: 2017-9-10 20:55     标题: 批处理如何提取特定列的内容?

[attach]10857[/attach][attach]10858[/attach]
如附件所示,我需要将带有DNI特性的行列内容提取出来,应该怎么做尼?我试过用DNI作为关键字去扫描行,但是文件中有的不在一行上,例如C31,就会漏掉。大家有没有什么好办法?谢啦~~
作者: codegay    时间: 2017-9-11 11:52

这种文件格式 太不规范了。处理起来很麻烦。
作者: mmmike    时间: 2017-9-11 22:17

是啊,画图软件自动生成的器件列表,让我头疼了好久。怎么都for不出来
作者: codegay    时间: 2017-9-12 11:41

软件名提供一下看看。
找一下设置能看看能不能CSV格式。CSV格式对程序比较友好。
作者: 523066680    时间: 2017-9-12 12:22

本帖最后由 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. }
复制代码

作者: slore    时间: 2017-9-12 15:12

主要有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
复制代码

作者: slore    时间: 2017-9-12 15:17

写了个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
复制代码

作者: 523066680    时间: 2017-9-12 15:27

本帖最后由 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
复制代码

作者: mmmike    时间: 2017-9-12 21:26

感谢大家的热心的帮助;字符串截取太巧妙了!!!!!完全不需要考虑无用信息的干扰。




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2