usr1990
usr1990

Reputation: 21

How to keep the empty tokens in for loop

I need to create a script to read a csv file with the ';' char as field delimiter. I use a FOR /F loop like this:

@echo off
FOR /F "skip=1 tokens=1-7 delims=;" %%a in (file.csv) do (
    echo Ref: %%~a
    echo Gru: %%~b
    echo Sin: %%~c
    echo St: %%~d
    echo Ma: %%~e
    echo Or: %%~f
    echo Es: %%~g
    echo ----------------------
)

And the file has this structure:

A123;00;B123;0;0;;0;
A124;00;B124;5;0;20010984;0;

Some fields are empty, how can i store into 7 variables the content of each corresponding field?

Upvotes: 0

Views: 1324

Answers (2)

aschipfl
aschipfl

Reputation: 34949

The for /F loop collapses multiple adjacent delimiters into a single one. But you can work around that when you put the line string in between "" and replace every delimiter ; by ";", which leads to a string where each delimited item is enclosed in "", even blank ones, so adjacent ; become separated. Afterwards, the quotation marks can easily be removed by using the ~-modifier for the for meta-variable:

rem // Read file and loop through all (non-empty) lines:
for /F skip^=1^ usebackq^ delims^=^ eol^= %%L in ("file.csv") do (
    rem // Store current line string:
    set "LINE=%%L"
    rem // Toggle delayed expansion:
    setlocal EnableDelayedExpansion
    rem /* Surround whole line string in `""` and replace each `;` by `";"`, leading to
    rem    each item appearing in between `""`; the outer-most pair of quotes is needed
    rem    to tell `for /F` that its set is a literal string: */
    for /F "tokens=1-7 delims=;" %%a in (""!LINE:^;=";"!"") do (
        endlocal
        rem // Use the `~`-modifier to remove the surrounding quotes from each item:
        echo Ref: %%~a
        echo Gru: %%~b
        echo Sin: %%~c
        echo St: %%~d
        echo Ma: %%~e
        echo Or: %%~f
        echo Es: %%~g
        echo ----------------------
    )
)

This will fail in case any field in the input data contains ; on its own (in which case the field must be quoted).

Upvotes: 3

JosefZ
JosefZ

Reputation: 30153

You could accomplish the task easy using PowerShell:

powershell -noprofile -command "& {Import-Csv -Delimiter ';' -Path file.csv}"

If you insist upon batch-file then there exists a (non-trivial) solution:

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
FOR /F "eol=' skip=1 delims=" %%G in (file.csv) do (
  set "_line=%%~G"
  REM add a backslash (or other character) in front of every semicolon
  call set "_line=%%_line:;=\;%%"
  FOR /F "tokens=1-7 delims=;" %%a in ('call echo "%%_line%%"') do (
    call :callecho Ref: "%%~a"
    call :callecho Gru: "%%~b"
    call :callecho Sin: "%%~c"
    call :callecho St: "%%~d"
    call :callecho Ma: "%%~e"
    call :callecho Or: "%%~f"
    call :callecho Es: "%%~g"
    echo ----------------------
  )
)
ENDLOCAL
goto :eof

:callecho
  set "_item=%~2"
  REM display everything except the last character (=added space)
  set "_item=%_item:~0,-1%"
  SETLOCAL EnableDelayedExpansion
    echo(%~1 !_item!
  ENDLOCAL
goto :eof

Result: D:\bat\SO\61748659.bat

Ref: A&123
Gru: 00
Sin: B123
St: 0
Ma: 0
Or:
Es: g0
----------------------
Ref: A124
Gru:
Sin: B&124
St: 5
Ma: 0
Or: 20010984
Es: g0
----------------------

Using the following sample file: type file.csv

Ref;Gru;Sin;St;Ma;Or;Es;
A&123;00;B123;0;0;;g0;
A124;;B&124;5;0;20010984;g0;

Upvotes: 0

Related Questions