João Fernandes
João Fernandes

Reputation: 505

Batch File to replace a specific value that it's always on the same position on a txt file

I have set of files that differs between each others on content and number of rows. However, I want to increment always by 1 the 8th value of the first file line even if the files are different. The values are delimited by semi-colon and could be just a numeric value or a alpha-numeric (i.e. 123 or TBA1).

I've tried to use tokens and loops, but without success. I've just get to actually insert the value and after it the "+1" increment that I was trying to do. My attemps so far is right below

@Echo Off
Set "SrcFile=tf.fic"
Set "OutFile=ntf.text"
If Not Exist "%SrcFile%" Exit /B
(   For /F "UseBackQ EOL=, Tokens=1-8* Delims=;" %%A In ("%SrcFile%"
    ) Do For /F "Tokens=1-2* Delims=" %%I In ("%%H"
    ) Do Echo=%%A;%%B;%%C;%%D;%%E;%%F;%%G;%%I%%J+1;%%K)>"%OutFile%"

So, taking as an example a file like looks like this:

1;12;A;23;;23;ASD;TTA2;233;HD2;233
1;232;A;b;;A

The output file should have the following content:

1;12;A;23;;23;ASD;TTA3;233;HD2;233
1;232;A;b;;A

Note: some fields may be as empty (i.e. first line 5th field) and should be empty as well on the output file.

Upvotes: 0

Views: 164

Answers (3)

user6811411
user6811411

Reputation:

Just for comparison, at the cost of readability this PowerShell script could be condensed further:

## Q:\Test\2019\09\12\SO_57905573.ps1
$SrcFile = ".\tf.fic"
$OutFile = ".\ntf.text"

$Content = (Get-Content $SrcFile)
$Firstline = $Content[0] -split ';'
if($Firstline[7] -match '(\d+)$'){
  $Firstline[7]=$Firstline[7] -replace $Matches[1],(([int]$Matches[1])+1)
}
$Content[0] = $FirstLine -join ';'
$Content | Set-Content $OutFile

The index in PowerShell is zero based.

Upvotes: 1

TripeHound
TripeHound

Reputation: 2960

I've taken @LotPings comment ("batch isn't suited well for your task as for /f takes successive delimiters as only one") as a challenge and have come up with the following:

@echo off
setlocal enabledelayedexpansion

Set "SrcFile=tf.fic"
Set "OutFile=ntf.text"
If Not Exist "%SrcFile%" Exit /B
If     Exist "%OutFile%" del "%OutFile%"

set FIRST=Y
for /f "usebackq tokens=* delims=#" %%x in ( "%SrcFile%" ) do (
    set "LINE=%%x"
    if defined FIRST (
        set "HASH=!LINE:;=;#!"
        for /f "usebackq tokens=1-8,* delims=#" %%a in ( '!HASH!' ) do (
            set ALPHA=
            set NUM=
            for /f "tokens=1 delims=0123456789"                 %%y in ( "%%h" ) do set ALPHA=%%y
            for /f "tokens=1 delims=ABCDEFGHIJKLMNOPQRSTUVWXYZ" %%y in ( "%%h" ) do set NUM=%%y
            set /a NUM=NUM+1
            set "LINE=%%a%%b%%c%%d%%e%%f%%g!ALPHA!!NUM!;%%i"
            set "LINE=!LINE:#=!"
        )
        set FIRST=
    )
    >>"%OutFile%" echo !LINE!
)
echo ============================ Src
type "%SrcFile%"
echo ============================ Out
type "%OutFile%"
echo ============================

This works both when the eighth field is numeric:

============================ Src
1;12;A;23;;23;ASD;99;233
1;232;A;b;;A
============================ Out
1;12;A;23;;23;ASD;100;233
1;232;A;b;;A
============================

and when it is alphanumeric:

============================ Src
1;12;A;23;;23;ASD;TTA2;233
1;232;A;b;;A
============================ Out
1;12;A;23;;23;ASD;TTA3;233
1;232;A;b;;A
============================

Notes / Explanation

  • The main loop operates over all lines of the file, buffering each line in LINE. Special processing happens only for the first line (when FIRST is defined).
  • HASH is created from the first line by replacing all semicolons (;) with (;#), turning, for example, aaa;;bbb into aaa;#;#bbb.
  • NOTE: The choice of # is more-or-less arbitrary, so long as it will never appear in a real file.
  • The modified line can now be safely split into the first eight fields (%%a through %%h) and "all the rest" (%%i) as there will always be something between the delimiters, even for empty fields.
  • We now break the eighth field (%%h) into its (optional) alpha part (ALPHA) and its numeric part (NUM). Somewhat perversely, this relies on the fact that adjacent delimiters are "rolled-in to one": the alpha part is delimited by one or more digits; the numeric part is delimited by one or more letters.
  • NOTE: I am assuming that the eighth field is always an optional run of non-digits (e.g. TTA) followed by one or more digits (e.g. 2). If this is not always the case (e.g. if there can be letters after the digit(s)), then adjustments would need to be made.
  • NOTE: The current file only works for upper-case letters preceding the number. If lower-case letters, or other characters can be present, you would need to add these to the delims=ABC... clause.
  • Having split the eighth field into its constituent parts, we increment the numeric part (using SET /A).
  • We now reassemble the line. Because we split the line using #, the original ; delimiters are still present, so don't need adding. The only exception is the eighth field, which due to it being further split into two parts will have lost its semicolon.
  • Finally, we need to remove any left-over # characters we added. There won't be any in the first eight fields, but %%i (the "and all the rest" variable) may contain some.
  • NOTE: If there are only eight fields on the first line, the current script will add a trailing semicolon that wasn't there before. If this matters, it is left as an exercise for the reader. (Probably involving the conditional appending of ;%%i).

Upvotes: 1

user6811411
user6811411

Reputation:

Using some advanced techniques:

:: Q:\Test\2019\09\12\SO_57905573.cmd
@Echo Off & Setlocal EnableDelayedExpansion
Set "SrcFile=tf.fic"
Set "OutFile=ntf.text"
If Not Exist "%SrcFile%" Exit /B

Set /P "FirstLine=" <"%SrcFile%"
Rem create (pseudo)array from FirstLine using self modifying code
Set i=1
Set "FirstLineCol[!i!]=%FirstLine:;="&Set /a i+=1&Set "FirstLineCol[!i!]=%"
rem Set FirstLine

rem strip possible letters from Col[8] and retain number
for /f "delims=ABCDEFGHIJKLMNOPQRSTUVWXYZ" %%N in ("%FirstLineCol[8]%") Do Set /a "Num=%%N,Num1=%%N+1"
set "FirstLineCol[8]=!FirstLineCol[8]:%Num%=%Num1%!"

>"%OutFile%" (
  set /p "x=!FirstLineCol[1]!"<NUL
  for /l %%L in (2,1,%i%) Do set /p "x=;!FirstLineCol[%%L]!"<NUL
  echo(
  more +1 "%srcFile%"
)

type "%SrcFile%"
echo:
echo:
type "%OutFile%"

to yield this:

> Q:\Test\2019\09\12\SO_57905573.cmd
1;12;A;23;;23;ASD;TTA2;233;HD2;233
1;232;A;b;;A

1;12;A;23;;23;ASD;TTA3;233;HD2;233
1;232;A;b;;A

Upvotes: 0

Related Questions