badbatchcoder
Goto Top

Zahlen aus einer Zeichenfolge auslesen und verändern - Batch

Liebes Batch-Team,

ich versuche die ganze Zeit ein Skript zum Laufen zu bringen, womit die
Anzahl der Zeichen einer Zeichenfolge der Variable %digits% zugeordnet werden und
mit Hilfe einer FOR-Schleife im Anschluss jede Zahl in dieser Zeichenfolge mit x addiert wird.
(Mit %digits% wird später weiter gearbeitet.)

Hier mal ein Beispiel:

Ausgangszahlenfolge:
84KW0118PXM64PDJSK99IO

Als x nehmen wir jetzt mal "2", die verarbeitete Zahlenfolge sollte also so aussehen:
86KW0120PXM66PDJSK101IO


Ich hoffe das Prinzip ist aber generell klar. Ich weis es ist etwas kompliziert und der Anwendungs-
bereich für sowas ist den meisten wahrscheinlich auch ein Rätsel, aber ich hoffe mir kann hier
jemand ohne nervige Fragen zu stellen weiterhelfen =)

Unten findet ihr noch ein paar mehr Beispiele, ebenfalls für "x=2"

Und ja, mir ist bewusst, dass es wahrscheinlich mit Powershell einfacher gehen würde,
ich möchte hier aber Batch benutzen, da mein restliches Skript auch in Batch geschrieben
ist und Batch dazu noch um einiges schneller läuft. Auch dass ich schon einmal nach einem
Codeblock zur Bestimmung der Anzahl der Zeichen eines Strings gefragt habe, ist mir klar!
Der Code hat allerdings nur mit Zahlen, also nur Zeichenketten , die aus natürlichen Zahlen
bestehen funktioniert.

Vielen Dank im Voraus
LG BatchCoder


Weitere Beispiele:

00253HWJ099ZEN8UWN wird zu 00255HWJ101ZEN10UWN

025UWBX5BH917NPW0156 wird zu 027UWBX7BH919NPW0158

Content-Key: 615628

Url: https://administrator.de/contentid/615628

Printed on: April 26, 2024 at 10:04 o'clock

Mitglied: 146189
146189 Oct 23, 2020 updated at 14:06:37 (UTC)
Goto Top
@echo off &setlocal enabledelayedexpansion

set "str=00253HWJ099ZEN8UWN"  
set x=2
:: --------------------
set "strwork=%str% "  
REM Länge der Variablen ermitteln
call :strLength strLen "%str%"  
set /a strLen-=1

set "num="  
set "strnew="  
for /L %%a in (0 1 !strLen!) do (
	set char=!strwork:~%%a,1!
	echo !char!|findstr "[0-9]" >null 2>&1 && (  
		set "num=!num!!char!"  
	) || (
		if "!num!" NEQ "" (  
			for /f "tokens=1,* delims=0" %%b in ("!num!") do set num=%%b  
			set /a num+=%x%
			if %%a == !strLen! set "char="  
			set "strnew=!strnew!!num!!char!"  
			set "num="  
		) else (
			set "strnew=!strnew!!str:~%%a,1!"  
		)
	)
)
set "strnew=!strnew: =!"  

echo Original: %str%
echo New:      %strnew%

goto :eof

REM Makro zum ermitteln der Länge
:strLength
set "#=%~2"  
set length=0
:stringLengthLoop
if defined # (set #=%#:~1%&set /A length += 1&goto stringLengthLoop)
set "%~1=%length%"  
goto :eof
und Batch dazu noch um einiges schneller läuft.
Ein Gerücht unter nicht PShellern die es nicht besser wissen face-smile.
Member: rubberman
rubberman Oct 23, 2020 at 15:16:44 (UTC)
Goto Top
Zitat von @146189:
Ein Gerücht unter nicht PShellern die es nicht besser wissen face-smile.

Fast. Wenn man für alles was nicht mit Batch machbar ist immer wieder einen PS Schnipsel einbaut und somit jedes Mal einen neue PS Prozess erzeugt, dann wird es lahm. Das komplette Script gleich als PS ist vergleichbar schnell und man brauch die ganzen Workarounds nicht. In diesem Fall würde ich auch nie mit Batch rangehen. Man muss Zeichen für Zeichen verarbeiten, da Batch Regex nicht vernünftig supportet und jede Zahl mit vorangestellter 0 wird von SET /A als oktale Zahl interpretiert. Also ist Batch ungeeignet.

Aber aus Jux - Das zeichenweise Verarbeiten lässt sich vereinfachen. Proof of concept:
@echo off &setlocal EnableDelayedExpansion
set "str=00253HWJ099ZEN8UWN"  

for /f %%i in ('cmd /u /von /c "<nul set /p =!str!"^|find /v ""') do (  
  2>nul (set /a "1%%i") && (  
    echo %%i num
  ) || (
    echo %%i alpha
  )
)

pause
Steffen
Member: BadBatchCoder
BadBatchCoder Oct 25, 2020 at 09:17:59 (UTC)
Goto Top
Vielen Dank!
Funktioniert an sich perfekt, nur hätte ich hier doch nochmal
einen Änderungswunsch, ich hoffe das ist möglich.
Hier wird aus dem String "00253HWJ099ZEN8UWN" der String "255HWJ101ZEN10UWN".
Wichtig wäre aber, dass die beiden Nuller vor dem String beibehalten werden.
Der gewünschte String würde also folgendermaßen lauten: "00255HWJ0101ZEN10UWN"

Ganz oben in der ursprünglichen Frage habe ich erklärt, dass Nuller vor einer
Zahl in die Ziffernkette miteinbezogen werden sollen.
Das brauche ich aber nach einigen Tests doch anders. Übrige Nuller vor einer
Zahl sollen einfach bestehen bleiben und nicht zur Zahl dazugehören.

Beispiele für einzelne Zahlen:
Das Fettgedruckte sind die erkannten Zahlen, mit denen dann auch gerechnet
werden soll, die Nuller vor der Zahl werden übernommen.
000999 +2 =0001001
012 +2 =014
5462 +2 =5464
998 +2 =1000

Dazu noch eine Frage:
Wäre es kompliziert, das Ganze nochmal exakt umgekehrt in ein Skript zu formen?
Also quasi statt der Addition auch noch einmal ein kurzes Skript für die Subtraktion
solcher Strings auch mit Erkennung einzelner Zahlen zu schreiben?

Hier auch nochmal ein Beispiel dazu:
Hierbei wird von jeder Zahl/Zifferngruppe die "2" abgezogen.
Aus dem String "URN0100UEB243IB101UEB00012RE" sollte dann der String
"URN098UEB241IB99UEB00010RE" folgen.

Ich bräuchte also nochmal zwei neue Skripts. Eines soll die Zifferngruppen ohne
Nuller links vor der eigentlichen Zahl mit x addieren und dann den Platz, wo die
vorherige Zahl im String stand durch die Neue ersetzen und somit den neuen String bilden.
Das andere Skript soll das gleiche nur umgekehrt machen. Hierbei sollen also auch wieder
die Zahlen im String erkannt werden und von jeder Zahl einzeln die Zahl „x“ abgezogen
werden. Nuller vor der eigentlichen Zahl sollen auch hier ignoriert und einfach über-
nommen werden.

Einen funktionierenden Code für die Bestimmung der Anzahl der Stellen von Strings
habe ich ja jetzt schon. =)

Ich weis das ist viel Arbeit, aber ich hoffe sie können mir hier weiterhelfen.
Ach und sorry nochmal, dass ich das oben in der Frage falsch beschrieben habe.

Vielen Dank für deine Hilfe
LG BatchCoder
Member: rubberman
rubberman Oct 25, 2020 updated at 21:13:58 (UTC)
Goto Top
@echo off &setlocal EnableDelayedExpansion
for %%i in (84KW0118PXM64PDJSK99IO 00253HWJ099ZEN8UWN 025UWBX5BH917NPW0156 URN098UEB241IB99UEB00010RE 008_08_8_000_00_0) do (
  call :add_to_substr %%i 2 new
  echo %%i&echo !new!
  call :add_to_substr !new! -2 rev
  echo !rev!&echo(
)

pause
exit/b

:add_to_substr
setlocal EnableDelayedExpansion
set "out="&set "n="&set "nolead="&set "cntlead=0"&set "a=%~2"  
for /f %%c in ('cmd /u /c "<nul set/p =%~1"^|find /v ""') do 2>nul set/a "1%%c"&&(  
  if %%c==0 (if not defined nolead set/a "cntlead+=1") else set "nolead=1"  
  set "n=!n!%%c"  
)||(call :_n_&set "out=!out!%%c")  
call :_n_
endlocal&set "%~3=%out%"&exit/b  
:_n_
if !n!!cntlead!==0 exit/b
for /f "tokens=* delims=0" %%n in ("!n!") do set "n=%%n"  
if not defined n set/a "cntlead-=1"  
set/a "n+=a"  
for /l %%i in (1 1 !cntlead!) do set "n=0!n!"  
set "out=!out!!n!"&set "n="&set "nolead="&set "cntlead=0"&exit/b  
Logischerweise kann beim Subtrahieren nur Mist rauskommen. Die Information, ob aus 101 nun 99 oder 099 werden soll, ist unwiederbringlich verloren.
// EDIT: Ah, missverstanden. Du willst vorangestellte Nullen beibehalten. Code aktualisiert ...

Steffen
Member: rubberman
rubberman Oct 26, 2020 at 23:10:55 (UTC)
Goto Top
Noch mal etwas auf Performance getrimmt. Schneller wird's mit Batch dann aber nicht mehr ...
@echo off &setlocal EnableDelayedExpansion
for %%i in (84KW0118PXM64PDJSK99IO 00253HWJ099ZEN8UWN 025UWBX5BH917NPW0156 URN098UEB241IB99UEB00010RE 008_08_8_000_00_0) do (
  call :add_to_substr %%i 2 new
  echo %%i&echo !new!
  call :add_to_substr !new! -2 rev
  echo !rev!&echo(
)

pause
exit/b

:add_to_substr
setlocal EnableDelayedExpansion
set "out="&set "n="&set "nolead="&set "cntlead=0"&set "a=%~2"  
for /f %%c in ('cmd /u /c "<nul set/p =%~1"^|find /v ""') do 2>nul set/a "1%%c"&&(  
  if not defined nolead (if %%c==0 (set/a "cntlead+=1") else set "nolead=1")  
  set "n=!n!%%c"  
)||((if defined n call :_n_)&set "out=!out!%%c")  
if defined n call :_n_
endlocal&set "%~3=%out%"&exit/b  
:_n_
for /f "tokens=* delims=0" %%n in ("!n!") do set "n=%%n"  
if not defined n set/a "cntlead-=1"  
set/a "n+=a"  
for /l %%i in (1 1 !cntlead!) do set "n=0!n!"  
set "out=!out!!n!"&set "n="&set "nolead="&set "cntlead=0"&exit/b  
Steffen