[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文本处理] 【已解决】求助批处理提取特定文本并分列

本帖最后由 jave000 于 2021-9-10 10:12 编辑

同类搜索简述:
按创建和修改时间将一批文本文件,从一个文件夹批量复制到另一个文件夹,并且两个文件夹的路径中间都有一个变量,需要手动输入,以及其中一个路径涉及到桌面,但为了可以分享给同事使用,识别任意电脑名下的桌面路径。
同时对所有文本的内容,筛出以序号为行首的内容,并对其进行分列,再转换到csv文件,同时增加一列生成其文本文件名。
同时自动打开excel。
复杂度:多行文本在分列后,同一列的部分内容要归入同一个单元格。其中部分列的内容只有一行。
感谢楼下诸位

@powershell -c "Get-Content '%~0' | Select-Object -Skip 1 | Out-String | Invoke-Expression" & exit /b
set-location $PSScriptRoot
$jave = read-host "roject Model Folder"
$CXMPV = [Environment]::GetFolderPath("Desktop")
$order = "2,3,4,5,6,1"
$sour = "\\btssvr9\pds1\$jave\3d\\iso_dgn\MOC_2021\"
$dest = "$CXMPV\Print\"
do
{
    $minute = read-host "Minutes of Minutes"
    $minute = $minute.trim()
}
while ($minute -match "\D")
Get-ChildItem -Path $sour -File |
    Where-Object { ($_.CreationTime -gt (get-date).AddMinutes(-$minute)) -or ($_.LastWriteTime -gt (get-date).AddMinutes(-$minute)) } |
    foreach-object {
        write-host $_.fullname
        copy-item $_.fullname -Destination $dest
    }
Invoke-Item $sour
Remove-Item $dest* -Include z-mto.csv
if (-not ([string]::IsNullOrEmpty($args[0])))
{
    $sour = $args[0]
}
function zget-data()
{
    [System.Collections.ArrayList] $sirenas = @()
    $rem = "^\s{3}\d{1}|^\s{2}\d{2}|^\s{11,12}\S.+"
    $renfs = "(\w{4})(\w{1,4})?(\w{1,4})?(\w{1,5})?(.*)"
    $renfd = "`$1-`$2-`$3-`$4-`$5"
    $res = "`n(.{4})(.{46})(.{13})(.{15})(.+)((?:`n\s{11,12}.+)*)"
    #$res = "`n\s{2,3}(\d{1,2})\s{4,}(\S.+?\S)\s{2,}(\d+(?:X\d+)?)\s{2,}(\S+(?:\s\S+)*)\s{2,}(\d+(?:[.]\d+)?(?:\sM)?)((?:`n\s{11,12}.+)*)"
    $red = "`t`$1`t`$2`$6`t`$3`t`$4`t`$5::"
    Get-ChildItem -path $sour "*.prt" | foreach-object {
        write-host "  "$_.basename
        $nf = $_.basename.ToUpper() -replace $renfs,$renfd -replace "-+$","";
        $a = "`n" + ((get-content -Encoding utf8 -path $_.fullname ) -match $rem -join "`n") ;
        if ( $a.length -gt 1 )
        {
            $a = $a -replace $res,$red -replace "[ `n]+"," " -replace " *`t *","`t"
            $a = $a -replace ":","" -replace "::","`n" -replace "(?m)\sm$","" -replace "(?m)^(?=`t)",$nf
            $sirenas.add($a) | out-null
        }
    }
    $sirenas = $sirenas -split "`n"
    $reos = "^([^`t]*)`t([^`t]*)`t([^`t]*)`t([^`t]*)`t([^`t]*)`t([^`t]*)$"
    $reod = $order -replace ",","`t" -replace "(?=\d)","`$"
    $sirenas = $sirenas -replace $reos, $reod
    return $sirenas
}
function zout-csv()
{
    $reos = "^([^`t]*)`t([^`t]*)`t([^`t]*)`t([^`t]*)`t([^`t]*)`t([^`t]*)$"
    $reod = '"$1","$2","$3","$4","$5","$6"'
    $sirenas -replace $reos,$reod | out-file -encoding utf8 ($dest + "z-mto.csv")
}
function zout-excel()
{
    try
    {
        $Excel = New-Object -ComObject Excel.Application  -ErrorAction Stop
    }
    catch
    {
        return
    }
    $Excel.Visible = $true
    $Workbook = $Excel.Workbooks.Add()
    $Sheet = $Workbook.Worksheets.Item(1)
    $v = [string[,]]::new($sirenas.count,1)
    for ( $i =0 ; $i -lt $sirenas.count ; $i++ )
    {
        $v[$i,0] = $sirenas[$i]
    }
    $rng = "A1:A" +  $sirenas.count
    $Sheet.range($rng).value2 = $v
    $colA = $sheet.range("A1").EntireColumn
    $colrange = $sheet.range("A1")
    $colA.texttocolumns($colrange,1,1,$false,$true,$false,$false,$false) | out-null
    $sheet.columns.autofit() | out-null
    $Workbook.SaveAs(($PSScriptRoot + "\" + $dest))
    $excel.Quit()
    [system.GC]::Collect()
}
[System.Collections.ArrayList] $sirenas = @()
$sirenas = zget-data
zout-csv
zout-excel

  1. $pathSour = ".\prt"
  2. $fileDest = "22"
  3. if (-not ([string]::IsNullOrEmpty($args[0])))
  4. {
  5.     $pathSour = $args[0]
  6. }
  7. remove-item $fileDest*.*
  8. [System.Collections.ArrayList] $al = @()
  9. $rem = "^\s{3}\d{1}|^\s{2}\d{2}|^\s{11,12}\S.+"
  10. $renfs = "(\w{4})(\w{1,4})?(\w{1,4})?(\w{1,5})?(.*)"
  11. $renfd = "`$1-`$2-`$3-`$4-`$5"
  12. $res = "`n(.{4})(.{46})(.{13})(.{15})(.+)((?:`n\s{11,12}.+)*)"
  13. #$res = "`n\s{2,3}(\d{1,2})\s{4,}(\S.+?\S)\s{2,}(\d+(?:X\d+)?)\s{2,}(\S+(?:\s\S+)*)\s{2,}(\d+(?:[.]\d+)?(?:\sM)?)((?:`n\s{11,12}.+)*)"
  14. $red = "`t`$1`t`$2`$6`t`$3`t`$4`t`$5::"
  15. get-childitem -path $pathSour "*.prt" | foreach-object {
  16.     write-host "  "$_.basename
  17.     $nf = $_.basename.ToUpper() -replace $renfs,$renfd -replace "-+$","";
  18.     $a = "`n" + (((get-content -Encoding utf8 -path $_.fullname ) -match $rem) -join "`n") ;
  19.     if ( $a.length -gt 0 )
  20.     {
  21.         $a = $a -replace $res,$red -replace "[ `n]+"," " -replace " *`t *","`t"
  22.         $a = $a -replace "::$","" -replace "::","`n" -replace "(?m)\sm$","" -replace "(?m)^(?=`t)",$nf
  23.         $al.add($a) | out-null
  24.     }
  25. }
  26. $al | out-file -encoding utf8 ($fileDest + "-a.txt")
复制代码

TOP

回复 56# WHY


    尝试运行了一下,没有发现任何问题。
明天到公司再试试一些别的prt文件
感谢大神

TOP

回复 55# idwma


可能是运行模式不同,这个运行很慢。
我试了你的初始代码,生成的txt,复制到excel后会中间穿插空白列,序号和描述列也没有分开。但是更加完善了。
我把代码里的txt改成csv,生成的csv和刚才的txt一样大,但是分列很混乱了,没有想到这俩会有差别。
正文部分我一点也没看懂
末尾exit后还可以加代码我第一次见,也不知道是什么意思
涨知识了,谢谢

TOP

本帖最后由 WHY 于 2021-6-29 00:00 编辑

回复 51# jave000
  1. $fd  = 'E:\Test\PRT';     #存放prt文件的目录路径
  2. $reg = '(?-i)^\s+(\d+)\s+(.+)(?<!\s)\s+(\d+(?:X\d+)?)\s+(.+)(?<![\sX])\s+(\d+(?:\.\d+)?)(?>\s+M)?$';
  3. [Collections.ArrayList]$out = @();
  4.       
  5. forEach ( $f In (dir $fd -Filter *.prt) ){
  6.     $flag = $false;
  7.     $name = $f.BaseName.ToUpper();
  8.     $name = $name -replace '^(....)(....)(....)(.....)(.+)$', '$1-$2-$3-$4-$5';
  9.     forEach ( $s In @(gc $f.FullName) ){
  10.         if ( $s -match $reg ){
  11.             if ( $flag ){
  12.                 [void]$out.Add( '"' + ($arr -join '","') + '"' );
  13.             }
  14.             $arr = @( '', '', '', '', '', $name );
  15.             for ( $i=1; $i -le 5; $i++ ){ $arr[$i-1] = $matches[$i].Replace('"', '""'); }
  16.             $flag = $true;
  17.         } elseif ( $s -match '^ {11}(\S.*)'){
  18.             $arr[1] += ' ' + $matches[1].Replace('"', '""');
  19.         }
  20.     }
  21.     if ( $flag ){
  22.        [void]$out.Add(  '"' + ($arr -join '","') + '"' );
  23.     }
  24. }
  25. sc 1.csv $out;
复制代码
个别文件描述列本身包含了双引号,比如:mmdiv710ds22lr0121.prt,格式发生错乱
已修改。
1

评分人数

    • jave000: 大神代码,只看懂一点点技术 + 1

TOP

本帖最后由 idwma 于 2021-6-27 19:29 编辑

回复 52# jave000


    完美匹配
改一下加几个分号可以自动分
再改一下,分号还是不稳改制表符来分隔
@echo off&setlocal EnableDelayedExpansion
set out=aa.txt
set d=3
for /f "delims=" %%a in ('mshta "about:<script>new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write("\t\t");close();</script>"') do set tab=%%a

for /f "delims=" %%k in ('dir/b *.prt') do (
        set na=%%~nk
        set na=!na:~0,4!-!na:~4,4!-!na:~8,4!-!na:~12,5!-!na:~17!
        call :con
        for /f "delims=" %%i in (%%k) do (
                set b=%%i
                for /l %%j in (1,1,30) do (
                        if "!b:~0,3!" equ "  %%j" set e=!b:~0,85! & set d=0
                        if "!b:~0,4!" equ "   %%j" set e=!b:~0,85! & set d=0
                )
                if "!d!" equ "0" call :ff
                if  "!b:~0,11!" equ  "           " (if !b:~-3! neq NPD  set c=!c!!b:~11! & set d=1)
                if "!d!" equ "1" set f=!na! !tab! !eee!!c! !tab! !e:~50,13! !tab! !e:~63,15! !tab! !e:~-5!
                if "!d!" equ "0"   echo;!f! >> !out! && set "c=" & set "f=" & set d=1
                echo;!f!
        )
        set d=3
)
echo;!f! >> !out!
pause
exit

:ff
for /l %%m in (49,-1,1) do (
        set ee=!e:~0,49!
        set eee=!ee:~1,%%m!
        if not "!b:~%%m,1!" == " "  goto :EOF
)

:con
for %%m in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do call set na=%%na:%%m=%%m%%
1

评分人数

TOP

用这个正则,和宽度分列一样了
  1. $re2s = '^\s{2,3}(\d{1,2})\s{4,}(.+?)(?<=\S)\s{2,}(\d*(?:\s?X\d+)?)\s{2,}(\S+(?:\s\S+)*)\s{2,}([\d]+(?:[.]\d+)?(?:\sM)?)$'
复制代码

TOP

三种分列方式,对比,还是按宽度截取,最佳
  1. $pathSour = ".\prt"
  2. $fileDest = "11"
  3. [System.Collections.ArrayList] $alc = @()
  4. $res1 = "^\s{2,3}\d{1,2}\s{4}.+"
  5. $res2 = "^\s{11}\S.+"
  6. $rea = "$res1" + "|" + "$res2"
  7. $renfs = "(\w{4})(\w{1,4})?(\w{1,4})?(\w{1,5})?(.*)"
  8. $renfd = "`$1-`$2-`$3-`$4-`$5"
  9. $rew = "^(.{4})(.{46})(.{13})(.{15})(.+)"
  10. $re2s = '^\s{2,3}(\d{1,2})\s{4,}(.+?)(?<=\S)\s{2,}(\d+(?:X\d+)?)\s{2,}(\S+(?:\s\S+)*)\s{2,}([\d]+(?:[.]\d+)?(?:\sM)?)$'
  11. $re2d = "`t`$1`t`$2`t`$3`t`$4`t`$5"
  12. get-childitem -path $pathSour "*.prt" | foreach-object {
  13.     write-host $_.basename
  14.     $fc = (get-content -Encoding utf8 $_.fullname) -match $rea
  15.     for ($i = 0 ; $i -lt $fc.count ; $i++)
  16.     {
  17.         if ($fc[$i] -match "^\s{2}[\s\d]\d\s{4}")
  18.         {
  19.             $s1 = $fc[$i]
  20.             # 以3+空格
  21.             $a1 = (" " + $s1) -replace "(?<=\S)  (?=\d)","   " -split "   +"
  22.             $a1line1 = $a1 -join "`t"
  23.             #re2s
  24.             $a2line1 = $s1 -replace $re2s,$re2d
  25.             # 宽度
  26.             $s1 -match $rew | out-null
  27.             $aw = @("") * 6
  28.             for ($j = 1 ; $j -le 5 ; $j++)
  29.             {
  30.                 $aw[$j] = $matches[$j].trim()
  31.             }
  32.             $awline1 = $aw -join "`t"
  33.             
  34.             if ( ($a1line1 -ne $awline1 ) -or ($a2line1 -ne $awline1 ))
  35.             {
  36.                 $alc.add( $_.basename + "`n" + $s1) | out-null
  37.                 $alc.add( "1" + $a1line1 + "`n" + "2" + $a2line1 + "`n" + "w" + $awline1 + "`n" ) | out-null
  38.             }
  39.         }
  40.     }
  41. }
  42. $alc | out-file -encoding utf8 ($fileDest + "-c.txt")
复制代码
下面12w开头的行,对应三种方式
  1. mdiv610ab21lr0035
  2.   21    SEE PIPING SPECIAL SUPPORT DRAWING                     SS1139             1
  3. 1 21 SEE PIPING SPECIAL SUPPORT DRAWING SS1139 1
  4. 2  21    SEE PIPING SPECIAL SUPPORT DRAWING                     SS1139             1
  5. w 21 SEE PIPING SPECIAL SUPPORT DRAWING SS1139 1
复制代码

TOP

本帖最后由 jave000 于 2021-6-26 23:15 编辑

回复 49# idwma


你好,谢谢,运行有报错,但是我偶然运行出了一次结果,很接近需要了,只是4、4、4、5、1+的判断错了,可以下载我一楼发的附件链接
我在你代码里没看到有写路径,不知道这个路径是怎么从代码里体现出来的
“找不到 E:\Downloads\PRT\ffff.txt”

TOP

本帖最后由 jave000 于 2021-6-26 22:36 编辑

回复 48# WHY


    不知道为啥,这个论坛我上传不了附件和图片。
我的第二列是元件描述,这个描述包含了第二行第三行第四行等若干行,这些都要合并到第一行的描述里

样本(bisca321ag12lr009m1.prt):
   1    INSERTED NOZZLE, CS 9901, PP/UP-GF PIPE   200X50       I143276             1
           CLASS B, LAMINATED END, LAMINATED
           END, , DN 200 X 50 - 208 X 13 MATING
           DIMENSION 208 X 2.7


成品(自动分列,管号这一列放在哪无所谓,但要大写):
   1    INSERTED NOZZLE, CS 9901, PP/UP-GF PIPE CLASS B, LAMINATED END, LAMINATED END, , DN 200 X 50 - 208 X 13 MATING DIMENSION 208 X 2.7   200X50       I143276             1          BISC-A321-AG12-LR009-M1

TOP

最稳妥的应该这样:导出为csv格式。

TOP

本帖最后由 idwma 于 2021-6-26 10:41 编辑

新的灵感
稍做修改
@echo off&setlocal EnableDelayedExpansion
set out=ffff.txt
del !out!
set d=3

for /f "delims=" %%k in ('dir/b *.prt') do (
        set na=%%~nk
        set na=!na:~0,4!-!na:~5,4!-!na:~9,4!-!na:~12,5!-!na:~16!

        for /f "delims=" %%i in (%%k) do (
                set b=%%i
                for /l %%j in (1,1,30) do (
                        if "!b:~0,3!" equ "  %%j" set e=!b:~0,85! & set d=0
                        if "!b:~0,4!" equ "   %%j" set e=!b:~0,85! & set d=0
                )
                if  "!b:~0,11!" equ  "           " (if !b:~-3! neq NPD  set c=!c!!b:~11! & set d=1)
                if "!d!" equ "1" set f=!na!   !e:~0,49!!c!          !e:~-38!
                if "!d!" equ "0"   echo;!f! >> !out! && set "c=" & set "f=" & set d=1

        )
        set d=3
)
echo;!f! >> !out!

pause
1

评分人数

TOP

回复 46# jave000


    "一是描述这一列只显示第一行" 这句是个啥意思?
别的很好改
  1. $fd  = 'E:\Test\PRT';     #存放prt文件的目录路径
  2. $arr = @();
  3. $reg = '(?-i)^\s+(\d+)\s+(.+)(?<!\s)\s+(\d+(?:X\d+)?)\s+(.+)(?<![\sX])\s+(\d+(?:\.\d+)?)(?>\s+M)?$';
  4. forEach( $f In (dir $fd -Filter *.prt) ){
  5.     $s = $f.BaseName;
  6.     $s = $s -replace '^(....)(....)(....)(.....)(.+)$', '$1-$2-$3-$4-$5';
  7.     $arr += @(gc $f.FullName) -match $reg -replace $reg, ('"$1","$2","$3","$4","$5","' + $s + '"');
  8. }
  9. sc 1.csv $arr;
复制代码
1

评分人数

TOP

本帖最后由 newswan 于 2021-6-25 23:46 编辑
  1. $pathSour = ".\prt"
  2. $fileDest = "11"
  3. [System.Collections.ArrayList] $al2 = @()
  4. get-childitem -path $pathSour "*.prt" | foreach-object {
  5.     $nf = $_.basename.ToUpper()
  6.     $nf = $nf -replace "(\w{4})(\w{1,4})?(\w{1,4})?(\w{1,5})?(.*)","`$1-`$2-`$3-`$4-`$5" -replace "-+$",""
  7.     $fc = (get-content $_.fullname) -match ''^\s{2,3}\d{1,2}\s{4}.+|^\s{11}\S.+''
  8.     for ($i = 0 ; $i -lt $fc.count ; $i++)
  9.     {
  10.         if ($fc[$i] -match "^\s{2}[\s\d]\d\s{4}")
  11.         {
  12.             #$re = '^\s{2,3}(\d{1,2})\s{4}(.+)\s+([^\s]+)\s+([^\s]+)\s+([\d]+[.]?[\d]*\s?M?)$'
  13.             $re = '^(.{4})(.{46})(.{13})(.{16})(.+)'
  14.             $fc[$i] -match "$re" | out-null
  15.             $a = @("") * 6
  16.             $a[0] = $nf
  17.             for ($j = 1 ; $j -le 5 ; $j++)
  18.             {
  19.                 $a[$j] = $matches[$j].trim()
  20.             }
  21.             $a[5] = $a[5] -replace "\sm",""
  22.             while ($fc[$i+1] -match "^\s{11}\S")
  23.             {
  24.                 $a[2] = $a[2] + " " + $fc[$i+1].trim()
  25.                 $i += 1
  26.             }
  27.             $al2.add($a -join "`t") | out-null
  28.         }
  29.     }
  30. }
  31. $al2 | out-file ($fileDest + ".txt")
复制代码
1

评分人数

TOP

回复 45# WHY


感谢大神,我正在看正则符号争取早日看懂你的代码运行原理。
这里有三个状况,一是描述这一列只显示第一行;二是管道长度的单位“ M”没被删掉;三是没有显示所在文件对应的管号。
我努力学习,尽快做到虽然不会写,但是会改。
十分感谢

TOP

返回列表