我有一个包含一种列格式数据的文件。我需要将此文件用作输入文件,输出文件应采用多列格式。我需要一个可以进行转换的脚本的帮助。无论是PowerShell还是批处理都无关紧要。
输入文件内容:input.txt
商店1:
苹果
橙色
桃
结束
商店2:
树
园内
池
鸟
结束
store3:
大厦
路
桃
店内
杂货店
结束
输出文件应为:
商店1:1,商店:,store3:
苹果,树,建筑物
橙色,公园,道路
桃子,池塘,桃子
,鸟,商店
,,杂货店
答案 0 :(得分:2)
我知道这是一个噱头,但我把它当作自己的学习机会,因为我有代码也许其他人可以从中学习
$text = gc C:\temp\input.txt
$groups = ($text | out-string) -split 'the end' | ? {$_ -notmatch '^(?:\s+)?$'}
$columns = $groups | % {$_.trim().split("`n")[0]}
$rows = $groups | % {$_.trim().Split("`n").count - 2} | sort -desc | select -f 1
$result = 0..$rows | % {
$row = $_
$obj = New-Object psobject
0..$($columns.Count-1) | % {
$column = $columns[$_]
$store = $groups[$_].trim().split("`n")
$item = $store[$row+1]
$obj | Add-Member -MemberType NoteProperty -Name $column.trim() -Value $(if ($item) {$item.trim()})
}
$obj
}
$result | epcsv C:\temp\input.csv -NoTypeInformation
答案 1 :(得分:0)
这是一个纯粹的batch-file解决方案:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define global settings here:
set "INFILE=input.txt"
set "OUTFILE=output.txt"
set "HEAD=^store[1-9][0-9]*:$"
set "FOOT=^THE END$"
set "DELIM=,"
set /A "COL=0, ROW=0, MAX=0"
for /F "delims=" %%L in ('
findstr /N /R "^" "%INFILE%"
') do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LINE=!LINE:*:=!"
if defined HEAD (
if !COL! EQU 0 set /A "ROW=-1"
cmd /V /C "echo^(!LINE!"| > nul findstr /R /C:"%HEAD%" ^
&& if !ROW! LSS 0 set /A "COL+=1, ROW=0"
if defined FOOT (
cmd /V /C "echo^(!LINE!"| > nul findstr /R /C:"%FOOT%" ^
&& set /A "ROW=-1" || if !COL! GTR 0 if !ROW! GEQ 0 set /A "ROW+=1"
) else (
if !COL! GTR 0 set /A "ROW+=1"
)
) else (
if defined FOOT (
if !ROW! EQU 0 set /A "COL+=1"
cmd /V /C "echo^(!LINE!"| > nul findstr /R /C:"%FOOT%" ^
&& set /A "ROW=0" || set /A "ROW+=1"
) else (
if !COL! EQU 0 set /A "COL=1"
if defined LINE (
set /A "ROW+=1"
) else (
if !ROW! GTR 0 set /A "COL+=1"
set /A "ROW=0"
)
)
)
if !MAX! LSS !ROW! set /A "MAX=!ROW!"
for /F "tokens=1-3 delims=;" %%I in ("!COL!;!ROW!;!MAX!") do (
endlocal
if %%I GTR 0 if %%J GTR 0 (
set "COLLECT[%%I_%%J]=%%L"
)
set /A "COL=%%I, ROW=%%J, MAX=%%K"
)
)
setlocal EnableDelayedExpansion
> "%OUTFILE%" (
for /L %%J in (1,1,%MAX%) do (
set "LINE="
for /L %%I in (1,1,%COL%) do (
if %%I GTR 1 set "LINE=!LINE!!DELIM!"
if defined COLLECT[%%I_%%J] (
set "LINE=!LINE!!COLLECT[%%I_%%J]:*:=!"
)
)
echo(!LINE!
)
)
endlocal
endlocal
exit /B
这个脚本基本上收集类似数组的变量COLLECT[COL_ROW]
中的数据,其中COL
和ROW
分别表示列和行索引。代码由两个循环组成,第一个循环遍历给定的输入文件并将行文本分配给相关的数组元素。预定义的页眉和页脚字符串(或者,如果两者都未提供,则为任何空行)控制适用的COL
和ROW
索引的确定。 MAX
保存最大的行索引ROW
,因为数据块的大小可能不同,以便以后填充。第二个循环枚举收集的数据数组,为每列构建一行文本并将它们写入指定的输出文件。
标记为rem
的开头的代码部分定义了脚本的全局设置,例如输入文件(INFILE
),输出文件(OUTFILE
),页眉和页脚分别为HEAD
和FOOT
;两个findstr
- 兼容的正则表达式;其中一个或两个都可以为空)和分隔符(DELIM
)。
这种方法有4种模式:
页眉和页脚都是非空的:
标头非空,但页脚为空:
页脚非空,但标题为空:
页眉和页脚都是空的:
注意:强>
虽然问题缺乏海报的信息和尝试或研究,但我决定回答这个问题,因为手头的任务是一个非常有趣的挑战,用batch-file来解决。
编辑:以下代码是来自用户Aacini(不是来自aschipfl)的解决方案,此答案的原始海报给予了他的亲切许可。我被迫这样做,因为问题已经结束,我真的想发布我的代码!
@echo off
setlocal EnableDelayedExpansion
rem Initialize data for first store
set /A max=0, lines=0, store=0
for /F "delims=" %%a in (input.txt) do (
if "%%a" neq "THE END" (
rem Process the next line of this store
set /A lines+=1
for %%l in (!lines!) do (
if not defined line[%%l] (
rem This store have more lines than previous ones: initialize new line
for /L %%i in (1,1,!store!) do set "line[%%l]=!line[%%l]! ,"
)
rem Append new data to this line
set "line[%%l]=!line[%%l]!%%a,"
)
) else (
rem This store ends: get the maximum number of lines
if !lines! gtr !max! (
set "max=!lines!"
) else (
rem Enlarge the additional lines of previous stores, if any
set /A lines+=1
for /L %%i in (!lines!,1,!max!) do set "line[%%i]=!line[%%i]! ,"
)
rem Pass to next store
set /A lines=0, store+=1
)
)
rem Output all result lines
(for /L %%i in (1,1,%max%) do echo !line[%%i]:~0,-1!) > output.txt
输出:
store1:,store2:,store3:
apple, Tree, Building
orange, Park, Road
peach, Pond, peach
, Bird, store
, , Grocery
答案 2 :(得分:-1)
您可以将文本文件传输到此PowerShell脚本中。它使用PowerShell的CSV方言(包括引用字符)。
Begin {
# corresponds to (untransposed) records
$records = @()
# the current record
$this_record = @()
# maximum fields of any (untransposed) record
$max_fields = 0
}
Process {
If ($_ -eq "THE END") {
# Append the record to the array.
$records += ,$this_record
# Count the maximum number of fields (this will be the number of
# records when the data is transposed).
If ($this_record.Length -gt $max_fields) {
$max_fields = $this_record.Length
}
$this_record = @()
} ElseIf ($_.Trim() -eq "") {
# Ignore blank lines.
} Else {
# Append the field to the current record.
$this_record += $_
}
}
End {
# Transpose the fields
$objects = @()
For ($col=0; $col -lt $max_fields; $col+=1) {
# ConvertTo-CSV gets object properties. It doesn't implicitly
# operate on arrays the way we'd prefer.
$obj = New-Object PSCustomObject
For ($row=0; $row -lt $records.Length; $row+=1) {
# Create property names that sort lexically (zero-padded numbers).
$obj | Add-Member -MemberType NoteProperty `
-Name ("{00000}" -f $row) `
-Value $records[$row][$col]
}
$objects += $obj
}
# Convert to CSV, throw away the header
$objects | ConvertTo-CSV -NoTypeInformation | Select-Object -Skip 1
}
E.g。 PowerShell -NoProfile -ExecutionPolicy Bypass -File xpose.ps1 < input.txt
生成:
"store1:","store2:","store3:"
"apple","Tree","Building"
"orange","Park","Road"
"peach","Pond","peach"
,"Bird","store"
,,"Grocery"
答案 3 :(得分:-1)
这里有一些代码可以帮到你。研究这个!
appendcolumn.bat
@echo off
set i=1
for /f "tokens=*" %%x in ('more') do (
call :app !i! %%x
set /a i += 1
)
exit /b
:app
set line%1=!line%1!,%2
exit /b