标题: [文本处理] 批处理如何提取特定列的内容? [打印本页]
作者: 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脚本- use utf8;
- use Encode;
- use IO::Handle;
- use File::Slurp;
- STDOUT->autoflush(1);
-
- my $src = encode('gbk', "原始文本.txt");
- my @source = read_file( $src );
- my $idx = 0;
-
- #去掉抬头
- do { shift @source } until ( $source[0]=~/======/ );
- shift @source;
-
- my $flag = 0;
- while ( $idx <= $#source )
- {
- ($DNI, $Material) = (substr($source[$idx], 9, 3), substr($source[$idx], 76, 20));
- $Material=~s/\s//g;
-
- if ( $DNI eq "DNI" )
- {
- print $Material,"\n";
- $flag = 1;
- }
- else
- {
- if ( $DNI eq " " and $flag == 1 and $Material ne "" )
- {
- print $Material,"\n";
- }
- else
- {
- $flag = 0;
- }
- }
-
- $idx++;
- }
复制代码
作者: slore 时间: 2017-9-12 15:12
主要有C31这种行,不然直接 tokens=6, delims=空格就行了。
为了照顾这行的话,就只好按列宽把他们取出来自己拆分,然后判断上一次的DNI是否是[DNI],
是的话这段也截取出来。
另外,文本处理的话,还是建议不要用批处理了,同样的思路,代码量多,还有很多字符的限制,处理起来浪费时间,解决自己的问题,允许机器上装别的语言工具的话,
建议ruby,pyhon。有要求不能装其他的语言解释器的话,也建议使用VBS或JS,而不是批处理。
批处理的话,如下,如果使用ruby,估计也就20行左右(1/4的代码量,而且可读性还高)。- @echo off&setlocal enabledelayedexpansion
-
- set n=2
- for /f "tokens=1,2,3,4,5,6 delims= " %%a in (src.txt) do (
- set /a n+=1
- if not "x%%f"=="x" ( if "x%%b"=="x===" (
- call :headline "%%a" "%%b" "%%c" "%%d" "%%e" "%%f"
- goto :end_head
- ))
- )
-
- :end_head
- echo COLUMN_LEN:%id_len%, %type_len%, %num_len%, %name_len%, %qty_len%, %des_len%
- echo.
-
- set is_data_end=0
- for /f "skip=%n% delims=" %%a in (src.txt) do (
- call :AnalysisLine "%%a"
- if %is_data_end% NEQ 0 goto :end_data
- )
-
- :end_data
- pause
- goto :EOF
-
- :AnalysisLine
- set "AL_line=%~1"
- set AL_id=!AL_line:~0,%id_len%!
- set AL_type=!AL_line:~%type_start%,%type_len%!
- set AL_des=!AL_line:~%des_start%,%des_len%!
-
- if "x%AL_id%"=="x TOTAL" (
- set is_data_end=1
- goto :EOF
- )
-
- if "x%AL_type%"=="x " (
- set "AL_type=%AL_type_LAST%"
- )
-
- set AL_type_LAST=%AL_type%
-
- if "x%AL_type%"=="xDNI" (
- echo [%AL_des%]
- )
- goto :EOF
-
- :headline
- call :Len %1
- set id_len=%Len_Ret%
- call :Len %2
- set /a type_start=%id_len%+3
- set type_len=%Len_Ret%
- call :Len %3
- set num_len=%Len_Ret%
- call :Len %4
- set name_len=%Len_Ret%
- call :Len %5
- set qty_len=%Len_Ret%
- call :Len %6
- set /a des_start=%id_len%+%type_len%+%num_len%+%name_len%+%qty_len%+5*3
- set des_len=%Len_Ret%
- goto :EOF
-
-
- :Len
- set LenVar_i=0
- set LenVar_Str=%~1
- if "x%LenVar_Str%"=="x" (
- set /a Len_Ret=0
- goto :EOF
- )
- :Len_Loop
- set LenVar_c=!LenVar_Str:~%LenVar_i%,1!
- if "x%LenVar_c%"=="x" goto :Len_EndLoop
- set /a LenVar_i+=1
- goto :Len_Loop
-
- :Len_EndLoop
- set /a Len_Ret=LenVar_i
- goto :EOF
复制代码
作者: slore 时间: 2017-9-12 15:17
写了个ruby版的,5分钟吧。18行,还有4,5行变量定义。
截取,获取长度直接有属性方法,用起来就是方便。- lines = File.readlines('src.txt')
- dataline = false
- last_type = ''
- des_start = des_len = 0
-
- lines.each do |line|
- line.chomp! # 去掉结尾Windows上可能多的\r回车符
- if dataline == false && line[0, 6] == ' S.No.'
- line =~ /^( S.No. DNI .+Qty )(Ref Des +) COMPANY/ #正则匹配 标题
- des_start, des_len = $1.length, $2.length #保存Des的标题的开始和长度
- dataline = true
- elsif dataline == true
- type = line[9, 3] #DNI列固定?
- end
- break if line[0, 6] == ' TOTAL' #遇到TOTAL结束
- type = last_type if type == ' ' #如果type是3个空格,那么用上次type
- last_type = type #设置当前type为最后type
- puts "[#{line[des_start, des_len]}]" if type == 'DNI'
- end
复制代码
作者: 523066680 时间: 2017-9-12 15:27
本帖最后由 523066680 于 2017-9-12 15:31 编辑
因为这个表有些信息位置是固定的,也没有中文之类的字符,批处理截取还算可以- @echo off
- setlocal enabledelayedexpansion
- set "file=原始文本.txt"
- set /a flag = 0
-
- for /f "tokens=* delims=" %%a in ('type %file% ^| more +7 ') do (
- set "str=%%a"
- set DNI=!str:~9,3!
- set Material=!str:~76,20!
- set Material=!Material: =!
- if "!DNI!" == "DNI" (
- echo !DNI! !Material!
- set /a flag = 1
- ) else (
- if "!DNI!!flag!" == " 1" (
- if not "!Material!" == "" (
- echo !DNI! !Material!
- )
- ) else (
- set /a flag=0
- )
- )
- )
- pause
复制代码
作者: mmmike 时间: 2017-9-12 21:26
感谢大家的热心的帮助;字符串截取太巧妙了!!!!!完全不需要考虑无用信息的干扰。
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |