[英]How to multiply a column in an CSV sheet from a batch file in Windows
[英]How can I multiply all values in a csv using Powershell or Batch?
我有很多個人身份證號碼,需要自動下載。 我不想在我的機器上存儲數千個唯一的個人 ID,而是想將所有 ID 乘以隨機 integer,保存結果並刪除原始文件。
這將最終出現在 Excel 中,但由於組織政策,VBA 不是一個選項。 我無法安裝任何東西——僅限於 Windows 附帶的東西。 據我了解,Excel 的電源查詢在閱讀后無法刪除源文件,但我可能是錯的 - 如果是這樣,那可能是 go 的另一個方向。
csv 樣品(ID 不是真實的)
3465549,2504526,2504566,3465552,2506339,3465551,2317719,2506451,3465547,3465550
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
3465546,3465544,2506443,3465542,3465545,2506696,3465543,2506775,,
,,,,,,,,,
,,,,,,,,,
2356880,2356779,2356828,2356944,2356915,2356917,2356928,2356783,2356850,2356781
,,,,,,,,,
3441512,2467140,2571636,2571767,2571812,2467147,3441514,2571648,3441513,3441511
,,,,,,,,,
2380632,2380582,2380629,2380586,2380613,2380537,2380601,2380636,2380539,2380471
3221426,3221424,3221425,3221429,,,,,,
2571011,2486766,1704643,2571037,2571040,2571018,2571043,2570940,2486742,2486770
2950233,2950214,2950268,3152046,3152050,3152047,3152049,3152051,3152048,2950384
特征
所需 output
假設隨機 integer 為 2,這將產生:
6931098,5009052,5009132,6931104,5012678,6931102,4635438,5012902,6931094,6931100
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
6931092,6931088,5012886,6931084,6931090,5013392,6931086,5013550,,
,,,,,,,,,
,,,,,,,,,
4713760,4713558,4713656,4713888,4713830,4713834,4713856,4713566,4713700,4713562
,,,,,,,,,
6883024,4934280,5143272,5143534,5143624,4934294,6883028,5143296,6883026,6883022
,,,,,,,,,
4761264,4761164,4761258,4761172,4761226,4761074,4761202,4761272,4761078,4760942
6442852,6442848,6442850,6442858,,,,,,
5142022,4973532,3409286,5142074,5142080,5142036,5142086,5141880,4973484,4973540
5900466,5900428,5900536,6304092,6304100,6304094,6304098,6304102,6304096,5900768
我試過的
這個答案看起來很有希望,但它只處理一列。 我不知道如何調整它以使其接受任意數量的列。
@echo off
setlocal enabledelayedexpansion
FOR /F "tokens=1-18* delims=," %%A IN (mycsv.csv) DO (
set sum1="%%~C"
set /a cole=!sum1! * 2
echo %%~A,%%~B,%%~C,%%~D,!cole!
) >> output.csv
我不太了解這個基於 Powershell 的答案。
$csv = Import-Csv mycsv.csv
foreach ($row in $csv) {
[int]$row.B *= -1
[int]$row.F *= -1
}
$csv | Export-Csv output.csv
如果我嘗試使用它,它會返回
powershell : Exception setting "B": "The property 'B' cannot be found on this object. Verify that the property exists and can be
At line:1 char:1
+ powershell -ep Bypass .\t.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Exception setti...sts and can be :String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
set."
At C:\Users\user\OneDrive\Personal\t.ps1:3 char:3
+ [int]$row.B *= -1
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Exception setting "F": "The property 'F' cannot be found on this object. Verify that the property exists and can be
set."
At C:\Users\user\OneDrive\Personal\t.ps1:4 char:3
+ [int]$row.F *= -1
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Exception setting "B": "The property 'B' cannot be found on this object. Verify that the property exists and can be
set."
At C:\Users\user\OneDrive\Personal\t.ps1:3 char:3
+ [int]$row.B *= -1
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Exception setting "F": "The property 'F' cannot be found on this object. Verify that the property exists and can be
set."
At C:\Users\user\OneDrive\Personal\t.ps1:4 char:3
+ [int]$row.F *= -1
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
我假設 B 和 F 只是指 csv 中的行,但如果我理解錯誤消息(我可能不會),它們是必須定義的名稱(如何定義?)我還需要這個在所有行中工作有值,並跳過行內的空行和空列。 所以硬編碼要相乘的行和列在這里對我不起作用。
在黑暗中摸索,替換
[int]$row.B *= -1
[int]$row.F *= -1
和
[int]$row *= -1
返回
powershell : Cannot convert the "@{12=18}" value of type "System.Management.Automation.PSCustomObject" to type "System.Int32".
At line:1 char:1
+ powershell -ep Bypass .\t.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Cannot convert ..."System.Int32".:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
At C:\Users\user\OneDrive\Personal\t.ps1:3 char:3
+ [int]$row *= -1
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : ConvertToFinalInvalidCastException
Cannot convert the "@{12=}" value of type "System.Management.Automation.PSCustomObject" to type "System.Int32".
At C:\Users\user\OneDrive\Personal\t.ps1:3 char:3
+ [int]$row *= -1
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : ConvertToFinalInvalidCastException
假設 Csv 具有固定數量的列,將 Csv 的每一行上的值相乘的邏輯可以是這樣的:
function MultiplyRows {
[cmdletbinding()]
param(
[parameter(Mandatory, ValueFromPipeline)]
[object]$InputObject,
[int]$MultiplyBy = 2
)
begin { $isFirstObject = $true }
process {
if($isFirstObject) {
$headers = $InputObject.PSObject.Properties.Name
$isFirstObject = $false
}
$out = [ordered]@{}
foreach($prop in $headers) {
if(-not ($thisValue = [int]$InputObject.$prop)) {
$out[$prop] = $null
continue
}
$out[$prop] = $thisValue * $MultiplyBy
}
[pscustomobject]$out
}
}
Import-Csv ... | MultiplyRows -MultiplyBy 3 | ConvertTo-Csv
如果 Csv 沒有標題,您將需要確定它有多少列並使用Import-Csv
上的-Header
參數。
批處理文件中可用的for /F
循環將多個連續的分隔符組合為一個,因此您不能將它與逗號一起用作分隔符來讀取具有空單元格/值/字段的 CSV 文件。 但是,您可以使用它來讀取整行,並使用標准for
循環以逗號分隔每行,因為沒有字符?
, *
和<
, >
(因此for
不需要訪問文件系統來派生匹配的文件名,因此維護給定的字符串):
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=%~dp0data.csv" & rem // (full path to target file)
set "_SEPC=," & rem // (separator character)
set "_HEAD=" & rem // (set to something if header)
set /A "_MULT=%RANDOM%%%(1<<7)+1" & rem // (multiplicator; result < 2 Gi!)
set /A "_ZPAD=0" & rem // (optionally zero-pad to width)
setlocal EnableDelayedExpansion
if defined _HEAD (set "HEAD=") else (set "HEAD=#")
rem // Read file line by line:
for /F usebackq^ delims^=^ eol^= %%J in ("!_FILE!") do (
if defined HEAD (
set "LINE=%%J" & set "COLL=%_SEPC%"
rem // Iterate through separated items, even blank ones:
for %%I in ("!LINE:%_SEPC%=" "!") do (
rem // Retain blank items in case:
if not "%%~I"=="" (
rem set /A "ITEM=%%~I*_MULT"
rem // Multiply item and correctly handle zero-padded numbers:
set "ITEM=00000000%%~I" & set "ITEM=1!ITEM:~-9!"
set /A "ITEM%%=1000000000, ITEM*=_MULT"
rem // Optionally zero-pad resulting number:
if %_ZPAD% gtr 0 (
if "!ITEM:~,-%_ZPAD%!"=="" (
set "ITEM=000000000!ITEM!" & set "ITEM=!ITEM:~-10!"
set "ITEM=!ITEM:~-%_ZPAD%!"
)
)
rem // Append new number to new line string:
set "COLL=!COLL!%_SEPC%!ITEM!"
) else set "COLL=!COLL!%_SEPC%"
)
rem // Return current altered line string:
echo(!COLL:~2!
) else set "HEAD=#" & echo(%%J
)
endlocal
endlocal
exit /B
在頂部,將變量_MULT
設置為乘法因子,以便結果值始終小於 2 31 − 1,否則可能會因溢出而導致負值。
變量_ZPAD
定義了結果產品被填充到的寬度,方法是在它們前面加上足夠的零。 位數較多的數字不會被截斷。 零的最大數量為 10。當_ZPAD
設置為零或更少時,不會發生填充。
變量_HEAD
必須設置為某個值,以防 CSV 文件包含要保留的標題。
請注意,當 CSV 文件包含(帶引號的)字符串和/或單獨包含分隔符的帶引號的值時,此腳本將失敗。
該腳本,我們稱之為multiply.bat
,在控制台中返回結果行。 要將它們寫入文件,請使用重定向(假設 CSV 文件是當前目錄中的data.csv
):
multiply.bat "data.csv" > "data_NEW.csv"
要覆蓋原來的 CSV 文件,只需在之后執行以下命令行:
move /Y "data_NEW.csv" "data.csv"
這是我會這樣做的方式:
@echo off
setlocal EnableDelayedExpansion
rem Define the factor, use %random% here
set /A "factor=2"
(for /F "delims=" %%a in (input.txt) do (
rem Get a line and eliminate multiple commas
set "in=%%a"
set "in=!in:,,=!"
if "!in:~-1!" equ "," set "in=!in:~0,-1!"
if not defined in (
echo ,,,,,,,,,
) else (
call :multiplyRow
echo !out!
)
)) > output.txt
goto :EOF
:multiplyRow
rem Multiply the numbers by the factor and count missing commas
set "out="
set /A "n=9,num=factor*%in:,=" & set "out=!out!!num!," & set /A "n-=1,num=factor*%" & set "out=!out!!num!"
rem Insert missing commas
for /L %%i in (1,1,%n%) do set "out=!out!,"
exit /B
“魔術線” in:MultiplyRow 做了幾件事:它將%in%
字符串中的每個逗號分隔的數字乘以因子,並將每個結果連接到由逗號分隔out
字符串。 它還為每個處理的數字遞減逗號計數器。 如果您取消@echo off
(以及重定向到output.txt
文件)並仔細查看執行的代碼,您可能會以更清晰的方式欣賞這種機制。
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory
rem filenames, output filename are names that I use for testing and deliberately include names
rem which include spaces to make sure that the process works using such names.
rem These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "filename1=%sourcedir%\q70944027.txt"
SET "outfile=%destdir%\outfile.txt"
SET /a factor=2
SET "line="
(
FOR /f "usebackqdelims=" %%b IN ("%filename1%") DO (
IF DEFINED line (
SET "line=%%b"
CALL :process
) ELSE (ECHO %%b&SET "line=x")
)
)>"%outfile%"
GOTO :EOF
:process
IF "%line:,=%" == "" ECHO %line%&GOTO :eof
SET "outline="
FOR %%c IN ("%line:,=" "%") DO IF "%%~c" neq "" (SET /a column=%factor% * %%~c&SET "outline=!outline!,!column!"
) ELSE (SET "outline=!outline!,")
ECHO %outline:~1%
GOTO :eof
沒有提到任何行中是否可能缺少單列或數據是否可能包含前導零。
為for
語句加上括號允許將否則控制台 output 重定向到 output 文件。
for
從源文件中讀取每一行。 如果變量line
被初始化為空,那么第一行只是簡單地反芻並且line
設置為非空,因此可以通過 header 行。 最初將line
設置為某個值將處理每一行(即沒有 header 行)。
line
設置為從文件中讀取的行的文本,並由一個名為process
的子例程處理。
process
首先檢查line
是否只包含逗號,方法是用空替換每個逗號並檢查空字符串。 如果測試成功,則將逗號行反芻。
否則,將line
中的每個逗號替換為" "
並引用結果字符串; 用一個簡單for
處理這個,所以每個數據列都將被引用,每個空列將由""
表示; 全部用空格隔開。
通過將每個術語附加其處理后的形式和每個空元素附加任何內容來重建每一列
Echo
顯結果,除了第一個字符是逗號。
這在往返測試中幸存下來。 源數據在 TextIn.CSV 中,結果相乘的數據存儲在 TextOut.CSV 中。 然后通過相同的過程發送TextOut.CSV除以相同的隨機數。 function ProcessFile 采用“* 2”等值乘以 2,用“/2”等值除以 2。傳遞給它的第二個值是源文件的名稱。 我在此頁面上找到了公式 SET /A test=%RANDOM% * 100 / 32768 + 1: 如何在 BATCH 腳本中使用隨機數?
有幾件事情需要考慮:
@ECHO OFF & SETLOCAL ENABLEDELAYEDEXPANSION & GOTO :Start
:ParseLine
SET NewLine=
SET Line=%~1
SET Line=!Line:,,=,$#@,!
SET Line=!Line:,,=,$#@,!
IF "!Line:~0,1!" EQU "," SET Line=$#@!Line!
IF "!Line:~-1!" EQU "," SET Line=!Line!$#@
FOR /L %%N IN (1, 1, 10000) DO (
FOR /F "EOL=, TOKENS=1* DELIMS=," %%B IN ("!Line!") DO (
IF "%%B" EQU "$#@" (
SET Token=
) ELSE (
SET /A Token = %%B !MathOp!
)
SET NewLine=!NewLine!!Token!,
SET Line=%%C
)
IF "!Line!" EQU "" (
ECHO !NewLine:~0,-1!
GOTO :EOF
)
)
GOTO :EOF
:ProcessFile
SET MathOp=%~1
FOR /F "EOL= TOKENS=* DELIMS=" %%L IN (%~2) DO (
if "%%L" NEQ "" (
CALL :ParseLine "%%L"
) ELSE ECHO;
)
GOTO :EOF
:Start
SET /A RandomValue=%RANDOM% * 100 / 32768 + 1
ECHO RandomValue=%RandomValue%
CALL :ProcessFile "* %RandomValue%" TextIn.CSV > TextOut.CSV
CALL :ProcessFile "/ %RandomValue%" TextOut.CSV > RoundTrip.CSV
FC TextIn.CsV RoundTrip.CSV
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.