Replace n-th element in CSV string - windows

I try to replace the n-th element of a CSV string, without knowing his value. For example, here is my string :
*;*;*;element_to_replace;*;*
With * an undefined string, it can be anything.
So i tried to use :
for /F "delims=" %%w in (file\workstation) do (
set line=%%w
if !compt! NEQ 0 (
set new_line=!line:*;*;*;*=*;*;*;new_value!
#echo !new_line! >> file\tmp_workstation
) else (
#echo !header_workstation! >> file\tmp_workstation
)
set /A "compt+=1"
)
It doesn't work. Am i doing something wrong ?

#echo off
setlocal enabledelayedexpansion
REM you want to replace token 4:
for /f "tokens=1-4,* delims=;" %%a in (t.csv) do (
echo %%a;%%b;%%c;replaced;%%e
)
tokens=1-4,* means: take the first four tokens, the fifth token is "the rest of the line". %%a is the first token, %%b is the second one etc.
You want to write token1;token2;token3,"replacement string for the fourth token(%%d)";"rest of the line" (fifth token).

Supposing the * characters do not appear literally within your data and it does also not contain any ? marks, you could use the following code snippet:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "INFILE=file\workstation"
set "OUTFILE=file\tmp_workstation"
set "SEPARATOR=;"
set /A "COL_NUM=4"
set "COL_NEWVAL=new_value"
rem // A single redirection:
> "%OUTFILE%" (
set "HEADER=#"
rem // Read CSV file line by line:
for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
set "LINE=%%L"
if defined HEADER (
rem // Skip header from replacement:
set "NEW_LINE=%%L"
set "HEADER="
) else (
set "NEW_LINE=" & set "SEP=" & set /A "IDX=0"
rem // Toggle delayed expansion to not lose any `!`:
setlocal EnableDelayedExpansion
set "LINE=!LINE:"=""!^"
rem // Use standard `for` loop to enumerate column values:
for %%I in ("!LINE:%SEPARATOR%=","!") do (
endlocal
set /A "IDX+=1"
set "ITEM=%%~I"
setlocal EnableDelayedExpansion
rem // Replace column value if index matches:
if !IDX! EQU %COL_NUM% (
endlocal
set "ITEM=%COL_NEWVAL%"
setlocal EnableDelayedExpansion
) else (
if defined ITEM set "ITEM=!ITEM:""="!^"
)
rem /* Collect line string;
rem `for /F` loop to pass string beyond `endlocal` barrier: */
for /F delims^=^ eol^= %%E in ("!NEW_LINE!!SEP!!ITEM!") do (
endlocal
set "NEW_LINE=%%E"
setlocal EnableDelayedExpansion
)
endlocal
set "SEP=%SEPARATOR%"
setlocal EnableDelayedExpansion
)
endlocal
)
rem // Output newly built line:
setlocal EnableDelayedExpansion
echo(!NEW_LINE!
endlocal
)
)
endlocal
exit /B

Related

Batch - Get block of text between flags, output and iterate over all files

I've got a bunch of text files in a directory that have a block of text I want to extract between two strings into a new text file of a similar name. I've got the single file working but think I've come unstuck with looping through all .txt files. Maybe at the "goto" command?
Here is the original, single file code I used:
Batch File - Find two lines then copy everything between those lines
~Top Break
foobar
~ more data title
more foobar
~Bottom Break
Garbage data
I have this code that works for a single file called FileNumber1.txt.
#echo off
set "FIRSTLINE=~Top Break"
set "LASTLINE=~Bottom Break"
set "INFILE=FileNumber1.txt"
setlocal EnableExtensions DisableDelayedExpansion
set "FLAG="
> "%INFILE%_MyData.txt" (
rem findstr configured so that each line in a file is given a "1:" number and colon.
for /F "delims=" %%L in ('findstr /N "^" "%INFILE%"') do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
rem this LINE=!LINE:*:=! removes the any character before the Colon. *:
set "LINE=!LINE:*:=!"
rem this block of code checks to see if line of text = Firstline variable, if so FLAG = TRUE
if "!LINE!"=="%FIRSTLINE%" (
endlocal
set "FLAG=TRUE"
rem this block of code checks to see if line of text = Lastline variable, if so goto :Continue and end the loop
) else if "!LINE!"=="%LASTLINE%" (
endlocal
goto :CONTINUE
) else if defined FLAG (
echo(#!LINE!
endlocal
) else (
endlocal
)
)
)
:CONTINUE
endlocal
NewFile1_MyData.txt Output:
foobar
~ more data title
more foobar
I've tried to wrap this in another "FOR" loop that looks for all txt files in the same directory.
This is my code that isn't working.
#echo off
set "FIRSTLINE=~Top Break"
set "LASTLINE=~Bottom Break"
for /F %%f in (*.txt) do (
set "INFILE=%%f"
setlocal EnableExtensions DisableDelayedExpansion
set "FLAG="
> "%INFILE%_OldHeader.txt" (
rem findstr configured so that each line in a file is given a "1:" number and colon.
for /F "delims=" %%L in ('findstr /N "^" "%INFILE%"') do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
rem this LINE=!LINE:*:=! removes the any character before the Colon. *:
set "LINE=!LINE:*:=!"
rem this block of code checks to see if line of text = Firstline variable, if so FLAG = TRUE
if "!LINE!"=="%FIRSTLINE%" (
endlocal
set "FLAG=TRUE"
rem this block of code checks to see if line of text = Lastline variable, if so goto :Continue and end the loop
) else if "!LINE!"=="%LASTLINE%" (
endlocal
goto :CONTINUE
) else if defined FLAG (
echo(#!LINE!
endlocal
) else (
endlocal
)
)
)
endlocal
:CONTINUE
))
The Command window gets to the "for /F" statement and exits.
Mmm... I would change the method to extract the lines for a simpler one based on lines to skip at beginning of file and number of lines to extract. After that, I would use a for to process all files and call a subroutine to extract the lines:
#echo off
setlocal EnableDelayedExpansion
set "FirstLine=~Top Break"
set "LastLine=~Bottom Break"
rem Process all text files in this folder
for %%f in (*.txt) do (
rem Search for First line and Number of lines
set "FirstNum="
for /F "delims=:" %%n in ('findstr /C:"%FirstLine%" /C:"%LastLine%" /N "%%f"') do (
if not defined FirstNum (
set "FirstNum=%%n"
) else (
set /A "LastNum=%%n-FirstNum-1"
)
)
rem Copy the lines
call :CopyLines >"%%~Nf_MyData.out" "%%f", !FirstNum!, !LastNum!
)
ren *.out *.txt
goto :EOF
:CopyLines File, Skip, Num
set "Num=%3"
for /F "usebackq skip=%2 delims=" %%a in (%1) do (
setlocal DisableDelayedExpansion
echo %%a
endlocal
set /A Num-=1
if !Num! equ 0 exit /B
)
exit /B

Get a variable from filename string in windows batch

good day, i have a folder with 400 files and i want to print a "name" from the filenames
this is the structure
ej:
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
20201323223__vvcastrillon_12_17949951031375250_1601939874_live.mp4
2020323123_yessromero.g_17849208194340047_1601945592_live.mp4
2020323223_ziizii_08_17979840166310477_1601929868_live.mp4
and what i need is
vendo.perfil01
_vvcastrillon_12
yessromero.g
ziizii_08
Im try to loop in the files and separate whit the _ and extract the 2 and 3 token numeral conditioning but the result is wrong and missing variables
#echo off
setlocal EnableDelayedExpansion
:loop
SET max=5000
for /F "delims=" %%I in ('dir "*_*_*.mp4" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V "\\outdir\\"') do (for /F "eol=| tokens=2,3 delims=_" %%J in ("%%~nI") do (SET "var="&for /f "delims=0123456789" %%a in ("%%K") do SET var=%%a
if defined var ( set nam=%%J_%%K ) else ( set nam=%%J )
)
echo/!nam!
)
timeout 10 > nul
goto loop
i think the answer is remove the first number before the _ then the string _xxxxxx_xxxxxxx_live.mp4 at the end but i dont know how read in reverse the tokens
tanks for any help
Since you have got different numbers of _-separated items in your file names and even adjacent _, so using for /F to split them into specific tokens with delims=_ is not the best choice.
I would use a standard for-loop instead, which receives modified file names, namely with each _ replaced by " " and enclosed within "", which leads to SPACE-separated partial name items. So:
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
is changed to:
"20201323223" "vendo.perfil01" "17872513294967257" "1601950878" "live.mp4"
before looping. Within the loop implement an index counter and just append those items to a buffer whose index numbers lie within a certain range that depends on the total number of items.
Here is an example script that demonstrates what I mean:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0." & rem // (full path to target directory)
set "_MASK=*_*_*_*_live.mp4" & rem // (pattern to match file names)
set "_FILT=^[0123456789][0123456789]*_..*_[0123456789][0123456789]*_[0123456789][0123456789]*_live\.mp4$"
rem // (additional `findstr` filter for file names)
set /A "_POS=1" & rem /* (index of first `_`-separated item to extract;
rem `0` is the first item, `-1` is the last) */
set /A "_NUM=-4" & rem /* (number of `_`-separated items to extract;
rem `-1` means all up to the last item) */
rem // Change into target directory:
pushd "%_ROOT%" && (
rem // Loop through all matching non-hidden, non-system files:
for /F "delims= eol=|" %%F in ('
dir /B /A:-D-H-S "%_MASK%" ^| findstr /I /R /C:"%_FILT%"
') do (
rem // Store current file name, initialise item index, counter and buffer:
set "FILE=%%F" & set /A "IDX=-1, CNT=-1" & set "BUFF=_"
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Count number of items and store one less:
rem set "TEST=%FILE:_=" & set /A "CNT+=1" & set "TEST=%"
for %%I in ("!FILE:_=" "!") do set /A "CNT+=1"
rem // Determine item index position from given index and number:
if !_POS! lss 0 (set /A "BEG=CNT+_POS+1") else set /A "BEG=_POS"
if !_NUM! lss 0 (set /A "END=CNT+_NUM+1") else set /A "END=_POS+_NUM-1"
rem // Transport numbers over `endlocal` barrier:
for %%C in (!CNT!) do for %%B in (!BEG!) do for %%A in (!END!) do (
rem // Loop through `_`-separated items of file name:
for %%I in ("!FILE:_=" "!") do (
rem // Store current item, increment item index:
endlocal & set "ITEM=%%~I" & set /A "IDX+=1"
setlocal EnableDelayedExpansion
rem // Append current item to buffer if in range:
if !IDX! geq %%B if !IDX! leq %%A (
rem // Transport buffer over `endlocal` barrier:
for /F "delims=" %%E in ("BUFF=!BUFF!_!ITEM!") do (
endlocal & set "%%E"
setlocal EnableDelayedExpansion
)
)
)
)
rem // Return buffer:
echo(!BUFF:~2!
endlocal
)
rem // Return from target directory:
popd
)
endlocal
exit /B
Something like this should help:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1* delims=_." %%i in ('dir /b /s /a-d "*_*_*.mp4"2^>nul ^| findstr.exe /ILV "\\outdir\\"') do (
set "var=%%j"
for /f "tokens=2,* delims=_." %%a in ("%%j") do echo !var:_%%b=!
)
Keep in mind that using delims will also split on consecutive characters like double underscore. for those you need to predetermine which has double underscore and let the script add it for you.
#ECHO OFF
SETLOCAL
for %%a in (
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
20201323223__vvcastrillon_12_17949951031375250_1601939874_live.mp4
2020323123_yessromero.g_17849208194340047_1601945592_live.mp4
2020323223_ziizii_08_17979840166310477_1601929868_live.mp4
) do set "filename=%%a" &call :process&echo --------------------------------------
GOTO :EOF
:process
echo stage 1 %filename%
:: step 1 : delete all characters up to and including the first underscore
set "filename=%filename:*_=%"
echo stage 2 %filename%
:: step 2 : find all numeric strings of length 4 or more in remainder
call :strsgt4 %filename:_= %
:: step 3 : replace each numeric string of length 4 or more + preceding underscore with "/" (invalid filename character)
echo stage 3 %filename%
:proc3lp
if "%zapstrings%" neq " " for %%v in (%zapstrings%) do call set "filename=%%filename:_%%v=/%%"&call set "zapstrings=%%zapstrings: %%v=%%"&goto proc3lp
echo stage 4 %filename%
:: step 5 : Remove all charactersincluding and after the first "/"
for /f "delims=/" %%v in ("%filename%") do echo result %%v
goto :eof
:strsgt4
set "zapstrings= "
:strsgt4loop
set "test=%1"
if not defined test goto :eof
set "test=%test:~4%"
if defined test call :isnum %test%&if not defined notnumber set "zapstrings=%zapstrings% %1"
shift
goto strsgt4loop
:: Determine whether %1 is purely numeric
:isnum
SET "notnumber=9%~1"
FOR /l %%z IN (0,1,9) DO CALL SET "notnumber=%%notnumber:%%z=%%"
GOTO :eof
Really a question of working out what your rules are.
I decided that your rules were: string after the first underscore, until before the first subsequent underscore that precedes a numeric string or length greater than 3
The %%a loop simply submits a sequence of sample strings to :process
The inline comments should explain the remainder.

Parsing special characters in a for loop from a file to a variable

I'm trying to set a variable (Let's say, filehash is the variable name) from a file using batch file. Alas, I was stuck facing these two problems:
When it contains special characters, especially exclamation mark(s) as I'm using enableDelayedExpansion.
While doing that, I need to change & to & as well.
I've tried several solutions provided from various sources but none would fit my requirements.
Here's my current code:
#echo off
set grep=binaries\grep.exe
set fileindex=binaries\index.htm
set count=0
for /f "tokens=* delims=" %%a in (crc.dat) do (
set count=!count! + 1
set filehash=%%a
%grep% --ignore-case -w "!filehash!" %fileindex%>> list.dat
)
And an example of what's inside the crc.dat file:
Kabooom! Kablooey!
Kaboom & Kablooey
And the result using my current code above in list.dat:
Kabooom Kablooey
Kaboom & Kablooey
The result that I'm expecting in list.dat:
Kabooom! Kablooey!
Kaboom & Kablooey
I hope I conveyed my problem properly and thank you in advance!
To replace & by & in the input of grep, use this:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "grep=binaries\grep.exe"
set "fileindex=binaries\index.htm"
set "file=crc.dat"
set "list=list.dat"
rem // Initialise counter:
set /A "count=0"
> "%list%" (
for /F "usebackq delims=" %%a in ("%file%") do (
rem // Increment counter:
set /A "count+=1"
rem // Assign line string to variable:
set "lineitem=%%a"
rem // Toggle delayed expansion:
setlocal EnableDelayedExpansion
rem // Do sub-string replacement:
set "lineitem=!lineitem:&=&!"
rem // Execute `grep` command line:
"!grep!" --ignore-case -w "!lineitem!" "!fileindex!"
endlocal
)
)
rem // Return counter:
echo/%count%
endlocal
To replace & by & in the output of grep, use this:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "grep=binaries\grep.exe"
set "fileindex=binaries\index.htm"
set "file=crc.dat"
set "list=list.dat"
rem // Initialise counter:
set /A "count=0"
> "%list%" (
for /F "usebackq delims=" %%a in ("%file%") do (
rem // Increment counter:
set /A "count+=1"
rem // Execute `grep` command line and capture its output by `for /F`:
for /F "delims=" %%b in ('^""%grep%" --ignore-case -w "%%a" "%fileindex%"^"') do (
rem // Assign `grep` output to variable:
set "lineitem=%%b"
rem // Toggle delayed expansion:
setlocal EnableDelayedExpansion
rem // Do sub-string replacement:
set "lineitem=!lineitem:&=&!"
rem // Return modified string:
echo(!lineitem!
endlocal
)
)
)
rem // Return counter:
echo/%count%
endlocal
In general, to handle strings with exclamation marks, you must toggle delayed expansion, so that normal %-expanded variables and for variable references like %%a become expanded with delayed expansion disabled.
This is a solution which is delayedExpansion-free and able to replace & to &.
#echo off
set grep=binaries\grep.exe
set fileindex=binaries\index.htm
set count=0
for /f "tokens=* delims=" %%a in (crc.dat) do (
set /a count+=1
%grep% --ignore-case -w "%%a" %fileindex%>>temp.dat
)
powershell -Command "(gc temp.dat) -replace '&', '&' | sc list.dat"
del /f temp.dat
pause
exit /b
Some changed things:
set /a count+=1 = set /a count=%count%+1
The !fileHash! points to %%a, so why do we need it? %%a will work.
The powershell command replaces & with &.
Output the replaced content into the file.
Delete a temp file used.

Windows Batch file count numbers of tokens

I have this batch file:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
IF EXIST OPERATORS_FULL.csv DEL OPERATORS_FULL.csv
IF EXIST OPERATORS_FULL.tmp DEL OPERATORS_FULL.tmp
FOR %%A IN ( OPERATORS_*.csv ) DO (
:: get attribute from filename
SET "attr=%%A"
SET "attr=!attr:OPERATORS_=!"
SET "attr=!attr:.csv=!"
:: split string to get date suffix
FOR /F "tokens=1,2 delims=_" %%G IN ( "!attr!" ) DO (
SET attr=%%G
SET date_=%%H
)
:: dump CSVs, skipping each header line, adding the attributes from the filename
FOR /F "skip=1 tokens=*" %%G IN ( %%A ) DO ECHO %%G;!attr!;!date_! >> OPERATORS_FULL.tmp
)
REN OPERATORS_FULL.tmp OPERATORS_FULL.csv
The attr value is variable and it can contain 1,2,3,4,... of "_" character.
So the tokens=1,2 is not functionally everytime.
I want the last token of the "attr" variable.
Any suggestions?
UPDATE
I tried this:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
IF EXIST Operatori_FULL.csv DEL Operatori_FULL.csv
IF EXIST Operatori_FULL.tmp DEL Operatori_FULL.tmp
FOR %%A IN ( Operatori_*.csv ) DO (
:: get attribute from filename
SET "attr=%%A"
SET "attr=!attr:Operatori_=!"
SET "attr=!attr:.csv=!"
set "date_=!attr!"
:loop
if "!date_:_=!" == "!date_!" goto :gotdate
for /f "delims=_ tokens=1,*" %%g in ("!date_!") do echo %%h
pause
goto :loop
:gotdate
:: dump CSVs, skipping each header line, adding the attributes from the filename
FOR /F "skip=1 tokens=*" %%G IN ( %%A ) DO ECHO %%G;!attr!;!date_! >> Operatori_FULL.tmp
)
REN Operatori_FULL.tmp Operatori_FULL.csv
But the snippet remove only the first part of string (A2A_)
This code extracts the last token from attr variable and store it in date_ variable:
rem split string to get date suffix
set "newAttr="
set "date_="
FOR %%G IN ( "!attr:_=" "!" ) DO (
SET "newAttr=!newAttr!_!date_!"
SET "date_=%%~G"
)
SET "attr=!newAttr:~2!"
If you just need the last token, the code is simpler:
FOR %%G IN ( "!attr:_=" "!" ) DO SET "date_=%%~G"
Here is a possible solution, that replaces every _ by a line-break temporarily:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "STRING=%~1" & rem // (first argument is taken as input string)
set "CHAR=_" & rem // (this is the character of interest)
rem // Build line-break:
(set ^"LF=^
%= empty line =%
^")
rem /* Replace each predefined character by a line-break,
rem and enclose every line string portion within `""`;
rem these quotation marks are needed to handle empty strings: */
setlocal EnableDelayedExpansion
if defined STRING set ^"STRING=^"!STRING:%CHAR%=^"^%LF%%LF%^"!^"^"
rem /* Loop through all the lines in the modified string and
rem assign each line string portion to a variable with
rem the surrounding `""` removed; when the loop is finished,
rem the last line is stored in the variable: */
for /F delims^=^ eol^= %%S in ("!STRING!") do (
endlocal
set "LAST=%%~S"
setlocal EnableDelayedExpansion
)
rem // Return string portion behind last predefined character:
echo(!LAST!
endlocal
endlocal
exit /B
Hopefully this will be close to what you want (not sure whether attr will be what you need):
#ECHO OFF
SETLOCAL EnableDelayedExpansion
IF EXIST Operatori_FULL.csv DEL Operatori_FULL.csv
IF EXIST Operatori_FULL.tmp DEL Operatori_FULL.tmp
FOR %%A IN ( Operatori_*.csv ) DO (
:: get attribute from filename
SET "attr=%%A"
SET "attr=!attr:Operatori_=!"
SET "attr=!attr:.csv=!"
set "date_=!attr!"
call :getLast
:: dump CSVs, skipping each header line, adding the attributes from the filename
FOR /F "skip=1 tokens=*" %%G IN ( %%A ) DO ECHO %%G;!attr!;!date_! >> Operatori_FULL.tmp
)
REN Operatori_FULL.tmp Operatori_FULL.csv
goto :eof
:getLast
if "!date_:_=!" == "!date_!" goto :eof
for /f "delims=_ tokens=1,*" %%g in ("!date_!") do set "date_=%h"
goto :getLast
The subroutine getLast will strip date_ to its last component (delimited by underscores). Its operation is: while there's an underscore in date_ it splits it into "the first token" and "all the rest" and sets date_ to "all the rest". When there are no (more) underscores, date_ is left with the last underscore-delimited component of its original value.
The "underscore stripping code" needs to be a "subroutine" since you cannot (to the best of my knowledge) use labels inside the outer for loop.

Loop through CSV file with batch - line break issue

This is extension to another question (Loop through CSV file with batch - Space issue)
I have csv file content like this
name,sex,age,description,date
venu,m,16,test mesg,2012-05-01
test,f,22,"He is good guy
and
brilliant",2012-05-01
I am looping this file using this command.
For /F "usebackq tokens=1-3 delims=" %%x in (test.csv) Do (
But since there is line break in second row, I am getting 3 records even though there are two records in the file.
How to fix this? Thanks in advance.
The main problem seems to be to count the quotes in a line.
If the count of quotes is odd then you need to append the next line and count again the quotes.
Counting of characters in a string is a bit tricky, if you won't iterate through all charachters.
I used here the delayed reduction technic, each quote will be effectivly replaced by a +1 and all other characters are removed.
To begin and terminate the line in a proper way there is always one extra +1 at the beginning, which will be compensated by a -1 in front.
The main trick is to replace the complete text from one quote to the next with exactly one +1 by replacing each quote with !!#:#=.
This works as !#:#=...<some text>...! will always be expanded to +1, as the content of the variable # is +1 and so the search pattern # can't be found.
The other replacements are only necessary to avoid problems with exclamation marks and carets int the text.
:::::::::::::::::::::::::::::::::::::::::::
:CountQuotes <stringVar> <result>
setlocal EnableDelayedExpansion
set "line=!%~1!"
set "#=+1"
rem DelayedExpansion: double all quotes
set "line=!line:"=""!"
rem DelayedExpansion: remove all carets ^
set "line=!line:^=!"
rem PercentExpansion: Remove all !
set "line=%line:!=%"
rem PercentExpansion: Replace double quotes to !!#:#=
set "line=-1^!#:#=%line:""=^!^!#:#=%"
for /F "delims=" %%X in ("!line!") do (
set /a count=%%X!
)
(
endlocal
set %~2=%count%
exit /b
)
And the logic for appending lines and inserting linefeeds
#echo off
setlocal DisableDelayedExpansion
set "lastLine="
set LF=^
rem Two empty lines
for /F "delims=" %%A in (test.csv) do (
set "line=%%A"
setlocal EnableDelayedExpansion
set "line=!line:\=\x!"
if defined lastLine (
set "line=!lastLine!\n!line!"
)
call :CountQuotes line quoteCnt
set /a rest=quoteCnt %% 2
if !rest! == 0 (
for %%L in ("!LF!") DO set "line=!line:\n=%%~L!"
set "line=!line:\\=\!"
echo Complete Row: !Line!
echo(
set "lastLine="
) ELSE (
set "lastLine=!line!"
)
for /F "delims=" %%X in (""!lastLine!"") DO (
endlocal
set "lastLine=%%~X"
)
)
exit /b
:::::::::::::::::::::::::::::::::::::::::::
:CountQuotes <stringVar> <result>
setlocal EnableDelayedExpansion
set "line=!%~1!"
set "#=+1"
rem DelayedExpansion: double all quotes
set "line=!line:"=""!"
rem DelayedExpansion: remove all carets ^
set "line=!line:^=!"
rem PercentExpansion: Remove all !
set "line=%line:!=%"
rem PercentExpansion: Replace double quotes to !!#:#=
set "line=-1^!#:#=%line:""=^!^!#:#=%"
for /F "delims=" %%X in ("!line!") do (
set /a count=%%X!
)
(
endlocal
set %~2=%count%
exit /b
)
The Batch file below do what you want:
#echo Off
setlocal EnableDelayedExpansion
call :processFile < test.csv
goto :EOF
:processFile
set line=
set /P line=
if not defined line exit /b
set "line=!line:,,=,#,!"
for %%a in (name sex age description mydate) do set %%a=
for %%a in (!line!) do (
if not defined name (
set "name=%%a"
) else if not defined sex (
set "sex=%%a"
) else if not defined age (
set "age=%%a"
) else if not defined description (
set "description=%%a"
) else if not defined mydate (
set "mydate=%%a"
)
)
:checkDate
if defined mydate goto show
set /P line=
for /F "tokens=1* delims=," %%a in ("!line!") do (
set "description=!description! %%a"
set "mydate=%%b"
)
goto checkDate
:show
for %%a in (name sex age description mydate) do set /P "=%%a=!%%a!, " < NUL
echo/
goto processFile
I added the requirements you requested in your previous topic, that is, the sex may be empty (and is changed by # character as I explained in my answer to that topic), and the name may include commas. I tested the program with this data file:
name,sex,age,description,date
venu,m,16,"test mesg",2012-05-01
test,,22,"He is good guy
and
brilliant",2012-05-01
"venu,gopal",m,16,"Another
multi-line
description",2012-05-02
And get these results:
name=name, sex=sex, age=age, description=description, mydate=date,
name=venu, sex=m, age=16, description="test mesg", mydate=2012-05-01,
name=test, sex=#, age=22, description="He is good guy and brilliant", mydate=2012-05-01,
name="venu,gopal", sex=m, age=16, description="Another multi-line description", mydate=2012-05-02,
Note that any field that contain commas or spaces must be enclosed in quotes.

Resources