About variable expansion

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
barnabe0057
Posts: 16
Joined: 04 Aug 2017 14:20
Location: France

About variable expansion

#1 Post by barnabe0057 » 18 Nov 2020 03:05

Hi guys,

I have a string whose numbers I would like to replace with ***, then each group of asterisks with a single asterisk.
The first FOR is working as expected, then I have a problem replacing the *** with a single *, the delayed expansion does not work, you can see it by the ECHO command that I added after the IFs.

Code: Select all

@echo off
setlocal enableextensions enabledelayedexpansion

set end_of_line=0
set "result="
set string=120400082_V1_UTR_HN512_gfhtgnnrt

for /L %%A in (0,1,9) do set "var=!var:%%A=*!"

for /L %%A in (0,1,254) do if not !end_of_line! EQU 1 (call :parse %%A)

echo.!result!
pause
exit

:parse

if "!string:~%1,1!"=="" (set end_of_line=1 & goto :eof)
if "!string:~%1,2!"=="**" (set "result=!result!*") else (set "result=!result!!string:~%1,1!")

echo.###%1 ###!string:~%1,2!
pause

goto :eof
Expected result : *_V*_UTR_HN*_gfhtgnnrt

Thank you in advance.

penpen
Expert
Posts: 1872
Joined: 23 Jun 2013 06:15
Location: Germany

Re: About variable expansion

#2 Post by penpen » 18 Nov 2020 07:05

You made some errors in your algorithm (not setting var to string and not using var after that, or using var instead of string in the first for-loop, ...).

In case you don't need to use a ":parse"-function, you could use string-replacement (untested; using # instaed of * for intermediate results):

Code: Select all

@echo off
setlocal enableextensions enabledelayedexpansion

set end_of_line=0
set "result="
set string=120400082_V1_UTR_HN512_gfhtgnnrt

set "var=!string!"
for /L %%A in (0,1,9) do set "var=!var:%%A=#!"
:: note: #maximum null terminated string length (including the trailing 0) =  8192 = 2^13
for /L %%A in (1,1,13) do set "var=!var:##=#!"
set "result=!var:#=*!"

echo.!result!
pause
exit
penpen

barnabe0057
Posts: 16
Joined: 04 Aug 2017 14:20
Location: France

Re: About variable expansion

#3 Post by barnabe0057 » 18 Nov 2020 07:56

Indeed I made a mistake by renaming the variables just before posting.

My first idea was to use string-replacement but I didn't get the expected result, the delayed expansion didn't work the way I wanted (=nest 2 delayed variables)
Well done for the second FOR I would not have found it myself (8192 = 2^13)

Thank you again for your answer, my problem is solved.
Last edited by barnabe0057 on 18 Nov 2020 08:05, edited 1 time in total.

jeb
Expert
Posts: 973
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: About variable expansion

#4 Post by jeb » 18 Nov 2020 08:04

Hi barnabe0057,

you used the variable "var" instead of "string".
Your replace logic can't work, because if you found two stars at a position you append to the current result a star, else you append the character at the position,
so you effectivly ALWAYS append the character at the current position.

I modified the code a bit.

Code: Select all

@echo off
setlocal enableextensions enabledelayedexpansion

set end_of_line=0
set "result="
set string=120400082_V1_UTR_HN512_gfhtgnnrt

for /L %%A in (0,1,9) do set "string=!string:%%A=*!"

for /L %%A in (0,1,254) do if not !end_of_line! EQU 1 (call :parse %%A)

echo --- !result!
exit /b

:parse
if "!string:~%1,1!"=="" (set end_of_line=1 & goto :eof)
if "!string:~%1,2!" NEQ "**" set "result=!result!!string:~%1,1!"

goto :eof
For better performance you could use the search/replace logic also for inflating the stars.

Code: Select all

for /L %%A in (0,1,9) do set "string=!string:%%A=#!"
for /L %%A in (0,1,12) do set "string=!string:##=#!"
set "string=!string:#=*!"
echo !string!
EDIT: I'm a little bit late, penpen already posted nearly the same answer while I was still writing ...

barnabe0057
Posts: 16
Joined: 04 Aug 2017 14:20
Location: France

Re: About variable expansion

#5 Post by barnabe0057 » 18 Nov 2020 08:48

Thank you jeb.

Eureka!
Posts: 111
Joined: 25 Jul 2019 18:25

Re: About variable expansion

#6 Post by Eureka! » 18 Nov 2020 10:30

If your string doesn't contain spaces ( it looks that way, based on your demo string ), you can also do something like this:

Code: Select all

@echo off
setlocal enabledelayedexpansion

set string=120400082_V1_UTR_HN512_gfhtgnnrt

for /L %%i in (0,1,9) DO set STRING=!STRING:%%i= !

if "%STRING:~0,1%"  EQU " " set PRE=*
if "%STRING:~-1%"   EQU " " set POST=*

for %%x in (%STRING%) DO set OUT=%%x*!OUT!

set OUT=%PRE%%OUT:~0,-1%%POST%
echo OUT = %OUT%

T3RRY
Posts: 97
Joined: 06 May 2020 10:14

Re: About variable expansion

#7 Post by T3RRY » 18 Nov 2020 12:34

A different approach again, less efficient though somewhat more flexible:

Code: Select all

@Echo off
Goto :main
rem /* Arg 1 and Arg 2 Mandatory; Arg Order fixed. Assumes max String Length 160 characters [arbitrary] */
:Substr [Varname] [remove string/s] [replace string] [Return Varname] [trim]
rem /* Arg 5 trim will remove leading and trailing replaced substring from the output string */
 Setlocal EnableDelayedExpansion
 Set "remChars=%~2"
 If not "%~3" == "" (
  Set "Sub=%~3"
 ) Else Set "Sub="
 Set "Sublen=0"
 For /L %%i in (0 1 50) Do If "!Sublen!" == "0" if "!Sub:~%%i,1!" == "" Set "Sublen=%%i"
 For /F "Delims=" %%G in ("!%1!")Do (
  Set "LastChar="
  Set "nStr="
  Set "tst=%%G"
  For /L %%i in (0 1 160) Do if Not "!tst:~%%i,1!" == "" (
   Set "CharType="
   For %%t in (!RemChars!) Do if "!tst:~%%i,1!" == "%%~t" Set "CharType=remove"
   If not "!LastChar!" == "" (
    If Not "!LastChar!" == "remove" If "!CharType!" == "remove" (Set "nStr=!nStr!!Sub!")
    If "!CharType!" == "" (Set "nStr=!nStr!!Tst:~%%i,1!")
    Set "LastChar=!CharType!"
   ) Else (
    If "!CharType!" == "remove" (
     Set "nStr=!nStr!!Sub!"
     Set "LastChar=remove"
    ) Else (
     Set "nStr=!nStr!!tst:~%%i,1!"
     Set "LastChar=retain"
 ))))
 If /I "%~5" == "trim" (
  If "!nStr:~0,%Sublen%!" == "!sub!" Set "nStr=!nStr:~%Sublen%,1000!"
  If "!nStr:~-%Sublen%!" == "!sub!" Set "nStr=!nStr:~0,-%Sublen%!"
 )
 If not "%~4" == "" (
  Endlocal & Set "%4=%nStr%"
 ) else (
  Endlocal & Set "%1=%nStr%"
 )
Exit /B 0

:main
Set "str=f2o_13r2e_x_a12m3p&l<>e"
Call :substr str "0 1 2 3 4 5 6 7 8 9" "*" mynewstr
set str
set mynewstr
Call :substr str "a b c d e f g h i j k l m n o p q r s t u v w x y z < > & _" ";" foobar trim
set foobar
Call :substr str "0 1 2 3 4 5 6 7 8 9 < > & _" "."
set str
Call :substr str .
set str
Output:

Code: Select all

str=f2o_13r2e_x_a12m3p&l<>e
mynewstr=f*o_*r*e_x_a*m*p&l<>e
foobar=2;13;2;12;3
str=f.o.r.e.x.a.m.p.l.e
str=forexample

Aacini
Expert
Posts: 1676
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: About variable expansion

#8 Post by Aacini » 18 Nov 2020 21:38

This simpler method works if the string start with number:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "result="
set "string=120400082_V1_UTR_HN512_gfhtgnnrt"

:parse
for /F "tokens=1* delims=0123456789" %%a in ("%string%") do set "result=!result!*%%a" & set "string=%%b"
if defined string goto parse

echo %result%
If the string may start with no-number, use this approach:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "digits=0123456789"
set "result="
set "string=XYZ120400082_V1_UTR_HN512_gfhtgnnrt"
set "var=%string%"

:parse
for /F "tokens=1* delims=0123456789" %%a in ("%string%") do set "result=!result!*%%a" & set "string=%%b"
if defined string goto parse

if "!digits:%var:~0,1%=!" equ "%digits%" set "result=%result:~1%"

echo %result%
Antonio

barnabe0057
Posts: 16
Joined: 04 Aug 2017 14:20
Location: France

Re: About variable expansion

#9 Post by barnabe0057 » 19 Nov 2020 02:00

Thank you Eureka! and T3RRY.

Very very very interesting Antonio ! I love your solution

Post Reply