:Concatenate function, advanced version, custom separator, multiple inputs, byval, byref and byref array ! (but oneprob)
Posted: 25 Sep 2023 03:10
Hi,
I needed to take all the elements of an array and make one string with them.
So I wrote this :Concatenate function which is very versatile and works in most cases
See below for a demonstration
First, you can give it arguments by value
result:
Arguments by reference
result :
Arguments by reference array
result:
You can specify a separator, here all the previous methods are used together
result:
And, you can change the moderator between each arguments
result:
Here is the full DEMO file
Includes a debug version to explain "the problem"
Now here is "the problem"
I would like to use a newline for the separator and without using enabledelayedexpansion too !
It almost works, the function works, but getting it past endlocal is proving to be a challenge.
Here is the code for that version
The output of that is, as expected
Here is the version with newline attempt
It does not work, no output is set
The problem is, the for loop that do the endlocal, break. So it stays in setlocal until GoTo :EOF at which point the data is lost.
I have created a debug version, it doesn't do much different, but it shows that it largely works except you can't get the data out !
Only solution I see is, a temp file, but I rather not !
If I am not mistaken this is a very high difficulty question this time !
Good luck
Here is the output of the debug version
Here is the debug code, it is not much help unfortunately
I needed to take all the elements of an array and make one string with them.
So I wrote this :Concatenate function which is very versatile and works in most cases
See below for a demonstration
Code: Select all
::Usage Call :Concatenate optional (SEPARATOR "X") InputArray1 InputArray2 InputArrayN OutputValue
:Concatenate
if "[%~1]" EQU "[SEPARATOR]" ( set "_Concatenate_separator=%~2" & shift & shift & GoTo :Concatenate )
set "_Concatenate_prefix=_CA"
if defined %1.ubound ( set "_Concatenate_input=%~1" ) else ( set "_Concatenate_input=Concatenate_placeholder" )
if defined %1.lbound call set /a _Concatenate_lbound=%%%~1.lbound%%
if defined %1.ubound call set /a _Concatenate_ubound=%%%~1.ubound%%
if not defined %1.lbound set /a "_Concatenate_lbound=0"
if not defined %1.ubound set /a "_Concatenate_ubound=0"
set /a "_Concatenate_index=%_Concatenate_lbound%"
setlocal enabledelayedexpansion
if not defined %1.lbound if not defined %1.ubound if not defined %_Concatenate_input%[%_Concatenate_index%] if defined %1 set %_Concatenate_input%[%_Concatenate_index%]=!%1!
if not defined %1.lbound if not defined %1.ubound if not defined %_Concatenate_input%[%_Concatenate_index%] set "%_Concatenate_input%[%_Concatenate_index%]=%~1"
if defined !_Concatenate_separator! ( set _Concatenate_separator=!%_Concatenate_separator%! )
if not defined _Concatenate_separator set "_Concatenate_separator= "
:Concatenate-loop
set _Concatenate_buffer=!_Concatenate_buffer!!%_Concatenate_input%[%_Concatenate_index%]!!_Concatenate_separator!
set /a "_Concatenate_index+=1"
if %_Concatenate_index% LEQ %_Concatenate_ubound% GoTo :Concatenate-loop
for /f "tokens=* delims=" %%a in ('echo.!_Concatenate_buffer!') do (
endlocal
set _Concatenate_buffer=%%a
)
if "[%~3]" NEQ "[]" ( shift & GoTo :Concatenate )
setlocal enabledelayedexpansion
for /f "tokens=* delims==" %%a in ('echo.!_Concatenate_buffer!') do (
endlocal
set %~2=%%a
)
Call :ClearVariablesByPrefix %_Concatenate_prefix% _Concatenate
GoTo :EOF
First, you can give it arguments by value
Code: Select all
Call :Concatenate "abc" "def" "ghi" OutputVar
Code: Select all
abc def ghi
Code: Select all
set myvar=jkl
set myothervar=mno
set myotherothervar=pqr
Call :Concatenate myvar myothervar myotherothervar OutputVar
Code: Select all
jkl mno pqr
Code: Select all
set myarray[0]=stu
set myarray[1]=vwx
set myarray[2]=yzA
set /a "myarray.ubound=2"
Call :Concatenate myarray OutputVar
Code: Select all
stu vwx yzA
Code: Select all
Call :Concatenate SEPARATOR 1 "abc" "def" "ghi" myvar myothervar myotherothervar myarray OutputVar
Code: Select all
abc1def1ghi1jkl1mno1pqr1stu1vwx1yzA1
Code: Select all
Call :Concatenate "abc" SEPARATOR 1 "def" "ghi" myvar SEPARATOR 2 myothervar myotherothervar SEPARATOR " " myarray OutputVar
Code: Select all
abc def1ghi1jkl1mno2pqr2stu vwx yzA
Includes a debug version to explain "the problem"
Now here is "the problem"
I would like to use a newline for the separator and without using enabledelayedexpansion too !
It almost works, the function works, but getting it past endlocal is proving to be a challenge.
Here is the code for that version
Code: Select all
set myarray[0]=Mary had a little lamb,
set myarray[1]=Its fleece was white as snow, yeah.
set myarray[2]=Everywhere the child went,
set myarray[3]=The little lamb was sure to go, yeah.
set /a "myarray.lbound=0"
set /a "myarray.ubound=3"
set "myarray2[-1]= "
set myarray2[0]=He followed her to school one day,
set myarray2[1]=And broke the teacher's rule.
set myarray2[2]=What a time did they have,
set myarray2[3]=That day at school.
set /a "myarray2.lbound=-1"
set /a "myarray2.ubound=3"
set "myarray3[-1]= "
set myarray3[0]=Tisket, tasket,
set myarray3[1]=A green and yellow basket.
set myarray3[2]=Sent a letter to my baby,
set myarray3[3]=On my way I passed it.
set /a "myarray3.lbound=-1"
set /a "myarray3.ubound=3"
echo -------------------------------
Call :Concatenate myarray myarray2 myarray3 _myConcatenatedString1
echo.&echo.&echo result for Call :Concatenate myarray myarray2 myarray3 _myConcatenatedString1
echo Demonstrate concatenate of all elements within 3 array, default separator of " " will be used
echo.&echo %_myConcatenatedString1%
Code: Select all
Mary had a little lamb, Its fleece was white as snow, yeah. Everywhere the child went, The little lamb was sure to go, yeah. He followed her to school one day, And broke the teacher's rule. What a time did they have, That day at school. Tisket, tasket, A green and yellow basket. Sent a letter to my baby, On my way I passed it.
Here is the version with newline attempt
It does not work, no output is set
Code: Select all
BTW you can specify SEPARATOR both byval and byref
rem Two empty lines above are essential
set newline=^
rem Two empty lines above are essential
set debug=true
echo.&echo.&echo.
Call :Concatenate SEPARATOR newline myarray myarray2 myarray3 TheOutput
echo.&echo.&echo result for Call :Concatenate SEPARATOR newline myarray myarray2 myarray3 TheOutput
echo.&echo %TheOutput%
I have created a debug version, it doesn't do much different, but it shows that it largely works except you can't get the data out !
Only solution I see is, a temp file, but I rather not !
If I am not mistaken this is a very high difficulty question this time !
Good luck
Here is the output of the debug version
Code: Select all
so close to working
Mary had a little lamb,
Its fleece was white as snow, yeah.
Everywhere the child went,
The little lamb was sure to go, yeah.
He followed her to school one day,
And broke the teacher's rule.
What a time did they have,
That day at school.
Tisket, tasket,
A green and yellow basket.
Sent a letter to my baby,
On my way I passed it.
but I can't get the text out of setlocal :(
set TheOutput=_Concatenate_buffer
result for Call :Concatenate SEPARATOR newline myarray myarray2 myarray3 TheOutput
ECHO is off.
Environment variable TheOutput not defined
Code: Select all
::Usage Call :Concatenate optional (SEPARATOR "X") InputArray1 InputArray2 InputArrayN OutputValue
:Concatenate-debug
if "[%~1]" EQU "[SEPARATOR]" ( set "_Concatenate_separator=%~2" & shift & shift & GoTo :Concatenate-debug )
set "_Concatenate_prefix=_CA"
if defined %1.ubound ( set "_Concatenate_input=%~1" ) else ( set "_Concatenate_input=Concatenate_placeholder" )
if defined %1.lbound call set /a _Concatenate_lbound=%%%~1.lbound%%
if defined %1.ubound call set /a _Concatenate_ubound=%%%~1.ubound%%
if not defined %1.lbound set /a "_Concatenate_lbound=0"
if not defined %1.ubound set /a "_Concatenate_ubound=0"
set /a "_Concatenate_index=%_Concatenate_lbound%"
setlocal enabledelayedexpansion
if not defined %1.lbound if not defined %1.ubound if not defined %_Concatenate_input%[%_Concatenate_index%] if defined %1 set %_Concatenate_input%[%_Concatenate_index%]=!%1!
if not defined %1.lbound if not defined %1.ubound if not defined %_Concatenate_input%[%_Concatenate_index%] set "%_Concatenate_input%[%_Concatenate_index%]=%~1"
if defined !_Concatenate_separator! ( set _Concatenate_separator=!%_Concatenate_separator%! )
if not defined _Concatenate_separator set "_Concatenate_separator= "
:Concatenate-debug-loop
set _Concatenate_buffer=!_Concatenate_buffer!!%_Concatenate_input%[%_Concatenate_index%]!!_Concatenate_separator!
set /a "_Concatenate_index+=1"
if %_Concatenate_index% LEQ %_Concatenate_ubound% GoTo :Concatenate-debug-loop
REM ----------DEBUG----------
if "[%debug%]" NEQ "[true]" for /f "tokens=* delims=" %%a in ('echo.!_Concatenate_buffer!') do (
endlocal
REM ----------DEBUG----------
if "[%debug%]" EQU "[true]" echo This never runs 1 a%%aa
REM ----------DEBUG----------
set _Concatenate_buffer=%%a
)
REM ----------DEBUG----------
if "[%~3]" NEQ "[]" ( shift & GoTo :Concatenate-debug )
REM ----------DEBUG----------
if "[%debug%]" EQU "[true]" ( echo so close to working&echo. )
if "[%debug%]" EQU "[true]" echo !_Concatenate_buffer!
if "[%debug%]" EQU "[true]" ( echo.&echo but I can't get the text out of setlocal :^( )
REM ----------DEBUG----------
setlocal enabledelayedexpansion
REM ----------DEBUG----------
if "[%debug%]" NEQ "[true]" for /f "tokens=* delims==" %%a in ('echo.!_Concatenate_buffer!') do (
endlocal
REM ----------DEBUG----------
if "[%debug%]" EQU "[true]" echo This never runs 2 a%%aa
REM ----------DEBUG----------
set %~2=%%a
)
REM ----------DEBUG----------
if "[%debug%]" EQU "[true]" echo set %~2=_Concatenate_buffer
REM if "[%debug%]" EQU "[true]" set %~2=!_Concatenate_buffer!
set %~2=!_Concatenate_buffer!
REM ----------DEBUG----------
if "[%debug%]" NEQ "[true]" Call :ClearVariablesByPrefix %_Concatenate_prefix% _Concatenate
REM ----------DEBUG----------
GoTo :EOF