Extracting substring from a batch or function argument

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Extracting substring from a batch or function argument

#16 Post by sambul35 » 31 May 2016 23:34

If you refer to this your snippet, not sure what "pctsmb1" means, but I'm getting the output below if Echo is On and opt=8, and Cmd memory is broken after that:

Code: Select all

K:\Tests>test1
ECHO is on.

K:\Tests>setlocal EnableDelayedExpansion

K:\Tests>set "opt=8"

K:\Tests>call :fun0 %% ""

One argument:
Originals: % 8
Substituting: '%'
Changing AnyVar does so change "%": % 8

Result: 8 8
AnyVar=%
%=8

Result2:

K:\Tests>call :fun1 "8" "opt"

Two arguments:
Originals: opt 8
Changing %2 changes "opt": opt 5

Result: 5 5

Result2:
Press any key to continue . . .

K:\Tests>


May be you modified that snippet in the meantime?

thefeduke
Posts: 211
Joined: 05 Apr 2015 13:06
Location: MA South Shore, USA

Re: Extracting substring from a batch or function argument

#17 Post by thefeduke » 31 May 2016 23:45

Thank you. I called mine pctsmb1.bat. you called yours test1.bat.
Your test does not give the code a chance. The premise from the very original first post was to pass it the argument "%opt%"
John A.

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Extracting substring from a batch or function argument

#18 Post by sambul35 » 01 Jun 2016 07:06

Ooops... sorry, don't know how I missed that. :oops:

Your substitution of a single variable with %%%1%% in a batch or function arguments does work well, and it seems to allow to program a function in a universal manner regardless of the variable name processed by it, thus eliminating the need to duplicate the variable name in arguments. Very interesting, and found nowhere else on the web I looked. This may add more flexibility to the validation function and simplify its code. Thanks :!:

douglas.swehla
Posts: 75
Joined: 01 Jun 2016 09:25

Re: Extracting substring from a batch or function argument

#19 Post by douglas.swehla » 01 Jun 2016 10:34

@sambul35: I'd like to understand better exactly what you're trying to accomplish, and in what context. If I read your comments and code correctly, you're trying to find a generic solution for the following sequence:
  1. Prompt the user for input.
  2. Compare the input to a list of acceptable values.
    • If the value is in the list, accept it without feedback and continue normally.
    • If the value is not in the list, give an error message, play a sound, and offer the user a chance to accept a default value.
      • If the user agrees to accept the default, or if the user takes no action, assign the default value to the input variable and continue normally.
      • If the user refuses to accept the default, send them back to the input prompt, and start over.

Questions:
  1. Is the above sequence correct? If not, please point out what's missing, and identify any incorrect assumptions.
  2. Will the user input and the list of authorized values always be single characters, or might they be multi-character strings?
  3. Do you want the option for custom messages, or are you content to always use "Invalid value" and "Set default value"?
  4. Are you committed to using the ringout.wav file for your sound, or can you use the built-in bell tone?
  5. Do you know for certain that none of your users are on Windows XP? (The CHOICE command is not available be default on NT, 2000, or XP.)
  6. Are you trying to have a "verification.bat" file that you can call from other batches, or a ":verification" subroutine that you can call within one batch?
  7. Are you expecting multiple inputs from a single user over the course of a session?
  8. What are you doing with the input once it's verified? Are you using it right away, or gathering multiple user inputs before proceeding?

An example script containing the whole "set up environment, prompt for input, verify input, use input" sequence as it currently exists would be helpful. Show the commands you used to test the code, and the output. If the output is not what you want, describe how it differs.

thefeduke
Posts: 211
Joined: 05 Apr 2015 13:06
Location: MA South Shore, USA

Re: Extracting substring from a batch or function argument

#20 Post by thefeduke » 01 Jun 2016 15:11

I am very pleased to hear that, Sambul35. Now I think that this can really be exploited.

I could not help thinking that all of this was inspired by the possibility that you were passing an argument to a script and having its value, you wanted to find the name that was used to pass it. I could never believe that anyone would want someone to key in such a string to call your script. However, knowing that you can't have your cake and eat it too does not prevent further creativity.

I have stumbled upon a method of passing such a string to a routine using a call within a script and not just from the command line. This method needs to suppress substitution of the variable.

First there is a demonstration script the I called PCTorEXCL.bat that will accept an argument in the form "%opt%" or "!opt!", where opt is any string (no blanks or uglies):

Code: Select all

@echo off
setlocal EnableDelayedExpansion
Call set InputVar=!%1!
IF "%InputVar%" EQU "" Call set InputVar=%%%1%%
Call set %InputVar%=x
echo/
Call Echo.Input argument has set variable name '%InputVar%' to value '%%%InputVar%%%'
Set "TempVar=%~2"
If /I "%TempVar%" EQU "" Set "TempVar=5"
echo.& call echo Result for variable %InputVar% was %%%InputVar%%% and is %tempvar% now^^!
( ENDLOCAL & REM RETURN VALUES
    call Set %InputVar%=%TempVar%
)
Echo.
exit /b
Note that this leaves the calling environment cluttered with a set value for whatever opt was and it must be undefined to work from the command line. That, however, is a good thing, if it is called from batch in a specific manner. Here is an example of the call:

Code: Select all

@echo off
::http://www.dostips.com/forum/viewtopic.php?p=46771#p46771
:: Post subject: Re: Extracting substring from a batch or function argument
::Modified: Jun 01, 2016 by TheFeDuke
setlocal DISABLEdelayedExpansion
echo/
set opt=z
echo Initial within caller: opt=%opt%
echo on
call PCTorEXCL "!opt!"
@echo off
echo New Value returned to caller opt=%opt%
endlocal
exit /b
The call to PCTorEXCL uses the "!" character associated with delayed expansion, which is DISabled at the time of the call, so the string sneaks through without substitution. The called routine tries to strip the argument with both "!" and "%%" and succeeds with the !"! null substitution in this case.

I think that this approach should open up even more options for you. But really, is it not easier to pass and work with the option name without having to strip off anything?

John.

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Extracting substring from a batch or function argument

#21 Post by sambul35 » 02 Jun 2016 09:16

douglas.swehla wrote:I'd like to understand better exactly what you're trying to accomplish, and in what context.

Thanks for the interesting questions. Basically, this thread is an attempt to figure out if a unified efficient approach is possible to decipher and verify various user inputs, entered:
a) as arguments when calling a batch manually or from a Task Scheduler
b) when the batch just started and may require additional typed input if some data missing in startup arguments
c) when various sections of the batch are executed

All input verification is ideally performed in a unified manner requiring minimal total batch code, and maximum re-use of more or less universal verification function(s).

Some folks post enormous size batches on this forum, where most of the code is devoted to verifying user input in a repetitive manner. While these batches may be easier for others to modify, they aren't necessarily represent the best approach to batch programming. A lot shorter code can do the same tasks faster, and with enough clarity for a trained user. In that regard we were trying to figure out above, what set of arguments is sufficient to perform the task, and how "missing" pieces can be derived from existing ones (i.e. by extracting substrings, delaying or disabling variable expansion, using related arguments, etc). The less arguments are entered for each, the more flexible but longer verification function code is.

As to answering your questions, the above are just code snippets, not necessarily representing any particular batch used in practice, but rather designed to reflect possible approaches to a generic solution.

Answers:
A. Yes for the snippet
B. It depends on each variable, hence the need for several verification options (i.e. validation methods)
C. Snippet with possibility of custom messages posted here
D. Using various ring tones is shown here
E. Yes
F. An integrated verification function is preferred
G. Yes, depending on completeness of the initial set of arguments entered when calling the batch
H. If startup arguments are incomplete for the tasks or erroneous, gathering more input may be required down the road, including when performing required batch tasks

How entered variables are used - they're printed to screen in the above snippet. :D Can you give some examples how is it important for the verification task? Did you mean they can be verified at application stage by checking the outcome? Possibly, but usually resulting in a longer code and unneeded iterations compare to verifying variables at entering. If you want to show a practical method implementing similar or your own approach to significantly shorten code, re-design of this FrameTool.bat, which also has a "lower half", may be an interesting though challenging starting point. :P
Last edited by sambul35 on 03 Jun 2016 05:10, edited 17 times in total.

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Extracting substring from a batch or function argument

#22 Post by sambul35 » 02 Jun 2016 09:32

thefeduke wrote:But really, is it not easier to pass and work with the option name without having to strip off anything?

May be... :o This seems to be the shortest code without redundancy, unless the calling sub name is transferred as a hidden arg similar to the call function name %~0 :

Code: Select all

@echo off
setlocal EnableDelayedExpansion
set "mes1=Invalid value" & set "mes2=Set default value" & echo/

:inp1
set /p "opt=Enter "opt" value > "
echo/ & call :fun0 "v" "klostu" "t" "opt" ":inp1"

:inp2
set /p "war=Enter "war" value > "
echo/ & call :fun0 "v" "0123456789" "5" "war" ":inp2"

:inp3
rem Set more variables...

:end
echo opt=!opt! & echo/
echo war=!war! & echo/
pause
endlocal
exit /b

:fun0
rem Verify typed variable values
set "lnk=" & set "cho="
if "%~1"=="v" (set "var="
   for /f "usebackq delims=%~2" %%k in (`echo !%~4!`) do (set "var=%%k")
   if defined var (set "cho=y")
) else if "%~1"=="k" ( rem Add another verification method here...
)
if defined cho ( powershell -c echo `a
   echo %mes1% & echo/
   choice /c yn /m "%mes2% %~3 ?" /t 10 /d !cho!
   echo/ & if !errorlevel! equ 1 (set "%~4=%~3") else (set "%~4=" & set "lnk=%~5"))
(goto) 2>nul & if not "!lnk!"=="" (goto !lnk!)
exit /b


It requires to maintain an argument matrix that ensures all variables avoid conflicting values overlap under the same argument number, so "argument number to value type" scheme remains the same, like default value is always %~3, lnk is always %~5, etc for all variables.
Last edited by sambul35 on 04 Jun 2016 15:00, edited 6 times in total.

thefeduke
Posts: 211
Joined: 05 Apr 2015 13:06
Location: MA South Shore, USA

Re: Extracting substring from a batch or function argument

#23 Post by thefeduke » 03 Jun 2016 14:19

sambul35 wrote:
thefeduke wrote:But really, is it not easier to pass and work with the option name without having to strip off anything?

May be... :o
I regret my above miscommunication. Am trying to support just one part of your mission: that of the generalized passed option name, receiving it and using it as transparently as possible. I am staying out of the functionality vs. number of arguments optimization dialog for now.

I was talking about the entry to the main script with the stripping comment. From what I can tell you can control the format of the call when you set up Task Scheduler. The users control their keystrokes when starting up. Would the user prefer to type - STARTINPUT "%MYPART%" - or - STARTINPUT MYPART - ? Or even, STARTINPUT? That is the interface where I question the need for stripping characters that do not need to be present.

These simple lines are the key to starting off:

Code: Select all

SetLocal EnableDelayedExpansion
Call Set "InputVar=!%1!"
If /I "%InputVar%" EQU ""   Call Set "InputVar=%%%1%%"
If /I "%InputVar%" EQU "%%" Call Set "InputVar=UnDefinedVar"
If /I "%InputVar%" EQU ""   Call Set "InputVar=%~1"
These lines can handle "%opt%" "!opt!" or opt with the same result in the generic option variable InputVar. Personally, I prefer the following code, which can accept from zero two two arguments and set up the generic variable and an initial value. The following example has "no meat". As I said before, I'll stay out of that part for now.

Code: Select all

@Echo Off
::http://www.dostips.com/forum/viewtopic.php?p=46771#p46771
:: Post subject: Re: Extracting substring from a batch or function argument
::Modified: Jun 03, 2016 by TheFeDuke
SetLocal EnableDelayedExpansion
Call Set "InputVar=!%1!"
If /I "%InputVar%" EQU ""   Call Set "InputVar=%%%1%%"
If /I "%InputVar%" EQU "%%" Call Set "InputVar=UnDefinedVar"
If /I "%InputVar%" EQU ""   Call Set "InputVar=%~1"
If /I "%InputVar%" EQU ""   Call Set "InputVar=OmittedVar"
Set "TempVar=%~2"&If /I "!TempVar!" EQU "" Set "TempVar=UnVerified"
Set "%InputVar%=%TempVar%"
::
:: Do validations and user interactions and such for selected values
:: This section can exercise the variables vs. internal code balance snippets
::
(ENDLOCAL&Call Set "LastInputVar=%InputVar%"&Call Set "%InputVar%=%TempVar%")
set "LastInputVar="
Exit /B
These defaults should be made more specific. I am also providing an example in the use of our pseudo-option variable. This one is somewhat interesting because the code calls itself recursively with a different arguments under certain conditions.

Code: Select all

@Echo Off
SetLocal EnableDelayedExpansion
Call Set "InputVar=!%1!"
If /I "%InputVar%" EQU ""   Call Set "InputVar=%%%1%%"
If /I "%InputVar%" EQU "%%" Call Set "InputVar=UnDefinedVar"
If /I "%InputVar%" EQU ""   Call Set "InputVar=%~1"
If /I "%InputVar%" EQU ""   Call Set "InputVar=OmittedVar"
Echo.&Call Echo.Input argument ONE has set variable name '%InputVar%' to value '%%%InputVar%%%'
Set "TempVar=%~2"&If /I "!TempVar!" EQU "" Set "TempVar=UnVerified"
Set "%InputVar%=%TempVar%"
Call Echo.Input argument TWO has set variable '%InputVar%' to value '%%%InputVar%%%'
::
::
:: Begin variable specific processing demo
:: Validations and user interactions and such for selected values
:: This section can exercise the variables vs. internal code balance snippets
Call Set "TempVar=%%%InputVar%%%"
If /I "%TempVar%" EQU "MySelf" Call "%~f0" InputVar "Yourself"
If /I "%Myself%" Equ "YourSelf" (
    Call Set "TempVar=Totally confused"
) Else (
    Call Set "TempVar=%%%InputVar%%%"
)
:: End a variable specific processing demo
::
(ENDLOCAL&Call Set "LastInputVar=%InputVar%"&Call Set "%InputVar%=%TempVar%")
Echo.&Call Echo.Returned a '%LastInputVar%' value of '%%%LastInputVar%%%'
set "LastInputVar="
Exit /B
Please note the lack of specific option names except for logic determination. I'll finish with the output of the last code when it is fed its trigger condition:

Code: Select all

C:\Users\Zani\Scripts>set my
Environment variable my not defined

C:\Users\Zani\Scripts>pxoption "%myself%" myself

Input argument ONE has set variable name 'myself' to value ''
Input argument TWO has set variable 'myself' to value 'myself'

Input argument ONE has set variable name 'myself' to value 'myself'
Input argument TWO has set variable 'myself' to value 'Yourself'

Returned a 'myself' value of 'Totally confused'

Returned a 'myself' value of 'Totally confused'

C:\Users\Zani\Scripts>set my
myself=Totally confused

C:\Users\Zani\Scripts>
Naturally, my choice of what to echo should be adjusted to taste.

John A.

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Extracting substring from a batch or function argument

#24 Post by sambul35 » 03 Jun 2016 18:59

Your "echo" choice sounds accurate. A new reader would likely say "these guys are definitely heading south". :mrgreen:

I'll get back to you on the above code after some reading comprehension. Don't forget however, the whole purpose of substitution in context of this thread is cutting down on number of function arguments to make the verification function more universal while short coded. Though of course an abstract "proof of concept" demo is useful too.

Post Reply