0
votes

Fichier batch pour remplacer une valeur spécifique qui est toujours à la même position sur un fichier txt

J'ai un ensemble de fichiers qui diffèrent les uns des autres sur le contenu et le nombre de lignes. Cependant, je veux toujours incrémenter de 1 la 8e valeur de la première ligne de fichier même si les fichiers sont différents. Les valeurs sont délimitées par des points-virgules et peuvent être simplement une valeur numérique ou alphanumérique (c'est-à-dire 123 ou TBA1).

J'ai essayé d'utiliser des jetons et des boucles, mais sans succès. Je viens juste d'insérer la valeur et ensuite l'incrément "+1" que j'essayais de faire. Mes tentatives jusqu'à présent sont juste en dessous

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

Donc, en prenant comme exemple un fichier comme ceci:

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

Le fichier de sortie doit avoir le contenu suivant:

@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%"

Remarque: certains champs peuvent être aussi vides (c'est-à-dire le cinquième champ de la première ligne) et doivent l'être également sur le fichier de sortie.


2 commentaires

Comme votre fichier source contient des champs vides ;; sans prendre de précautions, le lot ne convient pas bien à votre tâche car for / f prend les délimiteurs successifs comme un seul. PowerShell peut mieux s'adapter.


La boucle interne for / F n'a aucun sens puisque vous n'avez pas spécifié de délimitations , vous n'obtiendrez donc jamais plus d'un jetons . Ensuite, il y a le problème des champs vides. Et vous devez spécifier comment le huitième champ est construit; le préfixe TTA est-il toujours le même ou toujours 3 caractères? Plus vous êtes précis, moins nous avons à deviner, plus les réponses que vous obtiendrez seront adaptées ...


3 Réponses :


0
votes

En utilisant des techniques avancées:

> 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

pour obtenir ceci:

:: 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%"


0 commentaires

1
votes

J'ai pris le commentaire @LotPings (" batch n'est pas bien adapté à votre tâche car pour / f prend les délimiteurs successifs comme un seul ") comme un défi et j'ai proposé ce qui suit :

============================ 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
============================

Cela fonctionne à la fois lorsque le huitième champ est numérique:

============================ 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
============================

et lorsqu'il est alphanumérique:

@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 ============================

Notes / Explication

  • La boucle principale opère sur toutes les lignes du fichier, mettant en mémoire tampon chaque ligne dans LINE . Un traitement spécial n'a lieu que pour la première ligne (lorsque FIRST est défini).
  • HASH est créé à partir de la première ligne en remplaçant tous les points-virgules (; ) par (; # ), en tournant, par exemple, aaa ;; bbb en aaa; #; # bbb .
  • REMARQUE : le choix de # est plus ou moins arbitraire, tant qu'il n'apparaîtra jamais dans un fichier réel .
  • La ligne modifiée peut maintenant être divisée en toute sécurité dans les huit premiers champs ( %% a à %% h ) et "tout le reste" (% % i ) car il y aura toujours quelque chose entre les délimiteurs, même pour les champs vides.
  • Nous divisons maintenant le huitième champ ( %% h ) en sa partie alpha (facultative) ( ALPHA ) et sa partie numérique ( NUM code >). Un peu pervers, cela repose sur le fait que les délimiteurs adjacents sont "intégrés à un": la partie alpha est délimitée par un ou plusieurs chiffres; la partie numérique est délimitée par une ou plusieurs lettres.
  • REMARQUE : je suppose que le huitième champ est toujours une série facultative de non-chiffres (par exemple TTA ) suivi d'un ou plus de chiffres (par exemple 2 ). Si ce n'est pas toujours le cas (par exemple, s'il peut y avoir des lettres après le (s) chiffre (s)), des ajustements doivent être effectués.
  • REMARQUE : le fichier actuel ne fonctionne que pour les lettres majuscules précédant le nombre. Si des lettres minuscules ou d'autres caractères peuvent être présents, vous devrez les ajouter à la clause delims = ABC ... .
  • Après avoir divisé le huitième champ en ses parties constituantes, nous incrémentons la partie numérique (en utilisant SET / A ).
  • Nous réassemblons maintenant la ligne. Parce que nous avons divisé la ligne en utilisant # , les délimiteurs d'origine ; sont toujours présents, il n'est donc pas nécessaire d'ajouter. La seule exception est le huitième champ, qui, en raison de sa division en deux parties, aura perdu son point-virgule.
  • Enfin, nous devons supprimer tous les caractères # restants que nous avons ajoutés. Il n'y en aura pas dans les huit premiers champs, mais %% i (la variable "et tout le reste") peut en contenir.
  • REMARQUE : S'il n'y a que huit champs sur la première ligne, le script actuel ajoutera un point-virgule à la fin qui n'existait pas auparavant. Si cela compte, c'est un exercice pour le lecteur. (Impliquant probablement l'ajout conditionnel de ; %% i ).


0 commentaires

1
votes

Juste à titre de comparaison, au détriment de la lisibilité, ce script PowerShell pourrait être condensé davantage:

## 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

L'index dans PowerShell est basé sur zéro.


0 commentaires