Dos Batch Scripting: value passing, format issue. Nice Points!

Hi, I have obtained a way to trim leading and trailing spaces in a string. The answer is below, in the code snippet. This script returns a string in all cases, even if the input is all spaces within quotes, where the script will return "".

Now there is an input that is problematic for me. Pass it "  12 "1" 23  "", and the function will fail. However, if you only run the logic for removing the leading spaces, the input works.

So you get points if:
1. you can explain to me why this is happening,
2. you can provide a solution to the failure in the  trim trailing spaces segment,
3. you could make the input appear stripped of leading and trailing spaces as the output for the following batch script:

FOR %%a IN ("%~1", "%~2", "%~3", "%~4") DO (
  for /F "usebackq delims=" %%s in (`TrimLeadingAndTrailingSpaces.bat %%a`) do echo %%s
)

Best of luck,
airvector



set string=%~1
  echo What it looks like before [%string%]

  :leading
  if "%string:~0,1%"==" " (
    set string=%string:~1%
    goto leading
  )   
  
  echo to trailing
  
  :trailing
  if "%string:~-1%"==" " (
    set string=%string:~0,-1%
    goto trailing
  )

  :return
  echo What it looks like afterwards [%string%]
  echo "%string%"

Open in new window

airvectorAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Steve KnightIT ConsultancyCommented:
I imagined this was because there are two trailing " characters, and the ~1 bit removes the outer set leaving the inner one stuck there.  this then gets confused in the checks for the :trailing sub. I tried a batch method for this replacing the " with anothe character and putting it back but that came unstuck for other combinations...

However, in this case having tried it with this script I don't have any problems?!

trim "  12 "1" 23  "",

@echo off
set string=%~1
echo What it looks like before [%string%]

:leading
if "%string:~0,1%"==" " (
  set string=%string:~1%
  goto leading
)    

echo to trailing
:trailing
if "%string:~-1%"==" " (
  set string=%string:~0,-1%
  goto trailing
)

:return
echo What it looks like afterwards [%string%]

echo "%string%"

The outer for loop will choke on the funny " combinations, could I suggest instead bringing it all into one batch and using something like this:

@echo off
call :trimspaces "%~1"
call :trimspaces "%~2"
call :trimspaces "%~3"
call :trimspaces "%~4"
pause
exit /b

:trimspaces
set string=%~1
echo What it looks like before [%string%]

:leading
if "%string:~0,1%"==" " (
  set string=%string:~1%
  goto leading
)    

echo to trailing
:trailing
if "%string:~-1%"==" " (
  set string=%string:~0,-1%
  goto trailing
)

:return
echo What it looks like afterwards [%string%]

echo "%string%"

Output I get from that is:

[ C:\Utils\scripts]> trimtest "hello" "   test "  "left edkejde " "  12 "1" 23
""
What it looks like before [hello]
to trailing
What it looks like afterwards [hello]
"hello"
What it looks like before [   test ]
to trailing
What it looks like afterwards [test]
"test"
What it looks like before [left edkejde ]
to trailing
What it looks like afterwards [left edkejde]
"left edkejde"
What it looks like before [  12 "1" 23  "]
to trailing
What it looks like afterwards [12 "1" 23]
"12 "1" 23"
Press any key to continue . . .

Open in new window

0
t0t0Commented:
airvector

I have already responded to a similar question of yours (please refer back to it). I have subseqhently added the following code to that question.

The code below will take your input from the command line. All is needed is your two bits of code to remove leading and trailing spaces. See below.

For your information, I just tried the code with  "  12 "1" 23  "" and git back  12 "1" 23 as a single string of 9 characters. Is that what you expected? or are you expecting 3 seperate tokens '12' (2 characters long), '1' (Just 1 character) and '23' (2 characters long)?



   @echo off
   setlocal enabledelayedexpansion

   set string=%*
   set count=0

   echo.
   echo Command tail: [%string%]

   if not defined string (
      goto :end
   )

   if ^%string:~0,1%==^" (
      if ^%string:~-1%==^" (
         set string=%string:~1,-1%
      )
   )

   if not defined string (
      goto :end
   )

   :leading
   if "%string:~0,1%"==" " (
      set string=%string:~1%
      goto leading
   )

   :trailing
   if "%string:~-1%"==" " (
      set string=%string:~0,-1%
      goto trailing
   )

   :loop
      if not "!string:~%count%,1!"=="" (
      set /a count+=1
      goto loop
   )

   :end
   echo String:       [%string%]
   echo Length:       [%count%]

   exit /b %count%

0
t0t0Commented:
airvector
check this out!!


Steve
I'm surprised you disn't SHIFT the parameters as in the following code:




   @echo off
   setlocal enabledelayedexpansion
   
   echo.
   echo You input:
   echo.
     
   :loop
      set string=%~1
     
      :leading
      if "%string:~0,1%"==" " (
         set string=%string:~1%
         goto leading
      )

      :trailing
      if "%string:~-1%"==" " (
         set string=%string:~0,-1%
         goto trailing
      )
     
      echo [%string%]
      shift
   if not "%~1"=="" goto loop
0
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

t0t0Commented:
Oh, btw, my output was:
.
C:\Batch\EE\25718465>getparams "hello" "   test "  "left edkejde " "  12 "1" 23

You input:

[hello]
[test]
[left edkejde]
[12 "1" 23]

Open in new window

0
t0t0Commented:
Just removed a rogue double-quote character (see below) and got the ouput as indicated in the code window:


                                                                                                     rogue
                                                                                                         |
C:\Batch\EE\25718465>getparams "hello" "   test "  "left edkejde " "  12 "1" 23
.
.



C:\Batch\EE\25718465>getparams "hello" "   test "  "left edkejde "   12 "1" 23

You input:

[hello]
[test]
[left edkejde]
[12]
[1]
[23]

Open in new window

0
Bill PrewCommented:
==> airvector

==> Now there is an input that is problematic for me. Pass it "  12 "1" 23  "", and the function will
==> fail. However, if you only run the logic for removing the leading spaces, the input works.

I'm confused.  The string you show has 5 double quotes in it, that feels like an invalid string, I would think you at least always need an even number.  Am I missing something?

~bp
0
t0t0Commented:
To make this code (your code from above) work:

   @echo off
   FOR %%a IN ("%~1", "%~2", "%~3", "%~4") DO (
      for /F "usebackq delims=" %%s in (`TrimLeadingAndTrailingSpaces.bat %%a`) do echo %%s
   )


You will need the following batch file (named: TrimLeadingAndTrailingSpaces.bat):


   @echo off
   set string=%~1
   
   :leading
   if "%string:~0,1%"==" " (
      set string=%string:~1%
      goto leading
   )

   :trailing
   if "%string:~-1%"==" " (
      set string=%string:~0,-1%
      goto trailing
   )
   
   echo.%string%
0
t0t0Commented:
This is shorter:


To make this code (your code from above) work:

   @echo off
   FOR %%a IN ("%~1", "%~2", "%~3", "%~4") DO (
      for /F "usebackq delims=" %%s in (`TrimLeadingAndTrailingSpaces.bat %%a`) do echo %%s
   )


You will need the following batch file (named: TrimLeadingAndTrailingSpaces.bat):

   @echo.%~1



Yep, just a single line of code !!!

NOTE: As before, note the use of the full stop character.
0
t0t0Commented:
Try running this batch file on it's own.... I think nyou will be very surprised!


Try the same data as before. i.e.,:

   BATCH  "hello" "   test "  "left edkejde "   12 "1" 23
 


@echo off

:loop
   call :TrimLeadingAndTrailingSpaces %~1
   echo %string%
   shift
if not ^"%1==^" goto loop
exit /b

:TrimLeadingAndTrailingSpaces
set string=%*
0
Steve KnightIT ConsultancyCommented:
t0t0 - I couldnt get it to work reliably with his suggested string using a subroutine stripping the spaces, it always parsed into next token at the next ". Will have to give  thes suggestions a go too, wasnt aware oh history of the question.

0
Steve KnightIT ConsultancyCommented:
t0t0, that last one seems to split up the last entry into tokens for me:

C:\Utils\scripts>trim1 "hello" "   test "  "left edkejde "   12 "1" 23

hello
test
left edkejde
12
1
23

which may be the intention of course, nice technique though.

For the other technique I get this back:

C:\Utils\scripts>trim2 "hello" "   test "  "left edkejde "   12 "1" 23
hello
   test
left edkejde
12

as the fourth parameter is split into %1 %2 etc. by the " " I guess?
0
airvectorAuthor Commented:
t0t0, I placed the single-line echo with full stop in a batch and ran it on the problem input. The output gave me
  12 " "1" 23   "
which is fine on the right side, but the spaces on the left would have to be trimmed.

As for the other suggestions:
Dragon-it, using the exact same code as in OP, you didn't have any problems. On the other hand, I get the output you see at the bottom. And I get a similar problem using your code t0t0. However, again, in all code suggested, the input works if I remove the trailing segment. I can't figure out why.

As for the FOR loop code, I prefer testing it once I get the first batch code working. The purpose of the for loop in the second part of the qtn, keep in mind, will be used to run trimbla.bat on every item in the list output of another command (For lack of piping). I used ~1 ~2 ~3 ~4 to simplify my test.


prompt> TrimLeadingAndTrailingSpaces.bat "  12 "1" 23  ""
What it looks like before [  12 "1" 23  "]
to trailing
" ( was unexpected at this time.

Open in new window

0
AmazingTechCommented:
So how do you want the script to handle uneven number of quotes. Because you have 5 quotes in your example the input is taken as 1 parameter.
0
Bill PrewCommented:
AT,

Right, that was my question which is still unanswered...

~bp
0
airvectorAuthor Commented:
I want the input to be taken as 1 parameter, and echoed once as output.

Input: ["  12 "1" 23  ""]
output ["12 "1" 23  ""]

Open in new window

0
airvectorAuthor Commented:
This output is also ok, I'll just add quotes afterwards.
Output: [12 "1" 23  "]

Open in new window

0
Steve KnightIT ConsultancyCommented:
Double check there are no trailing spaces on any of the lines in the original script, especially copying from here you get them, I know I did from your script post above.  Just passing keyboard, will look later.
0
Bill PrewCommented:
I think you are going to have trouble working with strings that contain double quotes, and especially adjacent pairs of double qoutes, and even more so un matched double quotes.  For example, the following input will also be problematic:

""12" "1" "23""

I think using delayed expansion on your original script gets you what you want, but since I'm not 100% sure of the desired results under all conditions I'll let you decide that.

~bp
setlocal EnableDelayedExpansion
set string=%~1
echo What it looks like before [%string%]
 
:leading
if "!string:~0,1!" == " " (
  set string=!string:~1!
  goto leading
)
 
echo to trailing
 
:trailing
if "!string:~-1!" == " " (
  set string=!string:~0,-1!
  goto trailing
)
 
:return
echo What it looks like afterwards [!string!]
echo "!string!"

Open in new window

0
Bill PrewCommented:
I think the reason your original script doesn't work it because the command interpretter treats double quotes somewhat special, and especially pairs of double quotes.  As a result a simple statmment like

if "A"=="A" echo EQUAL

will work, but the following fails

if ""A"==""A" echo EQUAL

so if in a statement like

if "%var1%"=="%var2%" echo EQUAL

if either var has just a leading or trailing quote then the statement will fail.

By using delayed variable expansion, the interpretter doesn't actually see the value of the vars until it's actually time to execute the statement (not "parse" it), and so treats it differently, not seeing the pairs of double quotes on the input line.

Sorry, kind of a vague explanation but a hard topic to simplify.

~bp
0
airvectorAuthor Commented:
Well, using part of t0t0's code and billprew's code, I came up with what you see below. The first part of the answer done.
@echo off
setlocal EnableDelayedExpansion
set string=%*
echo What it looks like before [%string%]

if not defined string (
  goto :end
)
if ^%string:~0,1%==^" (
  if ^%string:~-1%==^" (
     set string=%string:~1,-1%
  )
)

 
:leading
if "!string:~0,1!" == " " (
  set string=!string:~1!
  goto leading
)
 
echo to trailing
 
:trailing
if "!string:~-1!" == " " (
  set string=!string:~0,-1!
  goto trailing
)
 
:return
echo What it looks like afterwards ["!string!"]
echo "!string!"

Open in new window

0
airvectorAuthor Commented:
Now the FOR loop. The script, the call, the output:
*******************
File: ForLoop.bat
*******************

@echo off
SETLOCAL EnableDelayedExpansion

FOR %%a IN ("%~1", "%~2", "%~3", "%~4") DO (
  for /F "usebackq delims=" %%s in (`TrimLeadingAndTrailingSpaces.bat %%a`) do echo %%s
)

**********************
Output with @echo off
**********************

Prompt> ForLoop.bat "  12 "1" 23  ""
%s
%s
%s

*************************
Output without @echo off
*************************

Prompt> ForLoop.bat "  12 "1" 23  ""

Prompt> SETLOCAL EnableDelayedExpansion

Prompt> FOR %a IN ("  12 "1" 23  "", "", "", "") DO ( for /F "usebackq delims=" %s in (`trim.bat %a`) do echo %s

Prompt> echo %s
%s

Prompt> echo %s
%s

Prompt> echo %s
%s

Prompt> 
Prompt>

Open in new window

0
airvectorAuthor Commented:
sorry for the name mismatch: above: trim.bat is actually TrimLeadingAndTrailingSpaces.bat
0
t0t0Commented:
airvector

Looking at 'your' code in 29953483... You have overlooked the essence and therefore need for the following REPEATED code:

   if not defined string (
      goto :end
   )


When you get to this code:

   if ^%string:~0,1%==^" (
      if ^%string:~-1%==^" (
         set string=%string:~1,-1%
      )
   )
 
if double-quotes appear at BOTH ends of the command tail, then they are stripped away. Therefore, you MUST take into account the possibility that a user might just enter a pair of empty double-quotes as his command tail. So, if these double-quotes are removed in the above section of code then we end up with NOTHING! That's why we need to RE-TEST whether %string% is defined or not otherwise, guess what will happen when the batch file moves onto the next section of code and tries to remove any trailing spaces?

Don't forget, I wrote the code, and I did it this way for this reason. It's no error that I repeated the code.

Therefore, you need this entire body of code:

   if not defined string (
      goto :end
   )

   if ^%string:~0,1%==^" (
      if ^%string:~-1%==^" (
         set string=%string:~1,-1%
      )
   )

   if not defined string (
      goto :end
   )


Of course, you could condense the code if you prefer to do so as in the following example:


   if not defined string goto :end
   if ^%string:~0,1%==^" if ^%string:~-1%==^" set string=%string:~1,-1%
   if not defined string goto :end



By the way, your code jumps to ':end' - there is no such label defined in your code!


Also, I dislike aborting programs in this manner - using GOTO :end or :EOF etc. I prefer to use 'EXIT /B', and the reason for that is you can use it to set an ERRORLEVEL code on exiting the batch file, like this:

   EXIT /B 1

This would set ERRORLEVEL to '1' meaning the batch file did not terminate normally, and therefore used as a precursor to diagnosing or just acknowledging the error.

Naturally, you'd normally want to end your batch file with 'EXIT /B 0' all being well.
 
0
t0t0Commented:
Whether I've missed this or not I can't recall right now (although I will look back later).

Please explain WHAT type of data you are parsing in the command tail.?....

I gather you're expecting FOUR items of data hence your code:

   FOR %%a IN ("%~1", "%~2", "%~3", "%~4") DO (...

So, what are you expecting %1, %2, %3 and %4 to hold? - Filename? integer values? Dates? Names? Etc. Etc..... Please be specific.

Knowing the answer to this is FUNDAMENTAL to writing a command line parsing routine.
 
0
airvectorAuthor Commented:
Also, I dislike aborting programs in this manner
Well, I'm more of the type that I don't like making code halt if there's an error. I prefer things continue, but with proper handling (like exception handling in javascript). So, I've adjusted my code to return "" if not defined, adding the line
if not defined string goto :end code
as you suggested. However, I replaced all jump to :end as jumps to :return

So, the FOR loop is to go through the output in list form of another command. This command outputs strings, so it could be anything you like, filenames, names, dates. However, the output values are excepted in any shape (quoted, not quoted, odd quotes, double-quotes, quoted with quotes with spaces inside, you name it).

Examples:


"12345"
" 12345 "
12345
"12"345"
" 12 " 345 "
12 " 345
12 " 345 "
" 12 " 345
""
"" 12 " 345 "
12 "  "  345
"  12  "  "  345

Open in new window

0
t0t0Commented:
please answer this

are you always only expecting FOUR items to be passed as parameters?

where are these items coming from? ie, user input? read from a file? piped from another process? etc, etc...

so far, your examples in your last comment suggest ONLY INTEGER values....

You say, a FOR-loop will collect output from another command and then in the body of that FOR-loop, you will validate the data collected one-at-a-time (or is it four-at-a-time?).

What is the command which will output the data you are collecting?

And what format will the output from 'that' command be?



I have a feeling you are making this as difficult as possible by not supplying information needed to get cracking on some code.

By the way, this is NOT a competition. We are experts who (in my case) enjoy solving problems using batch programming.
0
AmazingTechCommented:
So your example above would the afterwards look like this?

Or something close?
"12345"
"12345" 
"12345" 
"12"345" 
"12 " 345" 
"12 " 345"
"12 " 345 "" 
""12 " 345"
""
"" 12 " 345" 
"12 "  "  345"
"12  "  "  345"

Open in new window

0
AmazingTechCommented:
OK. My attached code is your new TrimLeadingAndTrailingSpaces.bat
Make sure the each line does not have spaces at the end. Copying code for some reasons pads each line with an extra space.

Don't use your FOR loop just simply call the bat.

call TrimLeadingAndTrailingSpaces.bat "12345"
call TrimLeadingAndTrailingSpaces.bat " 12345 "
call TrimLeadingAndTrailingSpaces.bat 12345
call TrimLeadingAndTrailingSpaces.bat "12"345"
call TrimLeadingAndTrailingSpaces.bat " 12 " 345 "
call TrimLeadingAndTrailingSpaces.bat 12 " 345
call TrimLeadingAndTrailingSpaces.bat 12 " 345 "
call TrimLeadingAndTrailingSpaces.bat " 12 " 345
call TrimLeadingAndTrailingSpaces.bat ""
call TrimLeadingAndTrailingSpaces.bat "" 12 " 345 "
call TrimLeadingAndTrailingSpaces.bat 12 "  "  345
call TrimLeadingAndTrailingSpaces.bat "  12  "  "  345

Of course if you still want to use another batch file to call TrimLeadingAndTrailingSpaces.bat then change your for loop to:

CALL TrimLeadingAndTrailingSpaces.bat %*
@ECHO off
  set string=%*
  if [^%string:~0,1%] == [^"] set string=%string:~1%
  if [^%string:~-1%] == [^"] set string=%string:~0,-1%

  echo What it looks like before [%string%]

  CALL :TRIM %string%
  GOTO :EOF
  :TRIM
  set string=%*
  echo What it looks like afterwards [%string%]
  echo "%string%"

Open in new window

0
AmazingTechCommented:
My output looks like this:

What it looks like before [12345]
What it looks like afterwards [12345]
"12345"
What it looks like before [ 12345 ]
What it looks like afterwards [12345]
"12345"
What it looks like before [12345]
What it looks like afterwards [12345]
"12345"
What it looks like before [12"345]
What it looks like afterwards [12"345]
"12"345"
What it looks like before [ 12 " 345 ]
What it looks like afterwards [12 " 345]
"12 " 345"
What it looks like before [12 " 345]
What it looks like afterwards [12 " 345]
"12 " 345"
What it looks like before [12 " 345 ]
What it looks like afterwards [12 " 345]
"12 " 345"
What it looks like before [ 12 " 345]
What it looks like afterwards [12 " 345]
"12 " 345"
What it looks like before []
What it looks like afterwards []
""
What it looks like before [" 12 " 345 ]
What it looks like afterwards [" 12 " 345]
"" 12 " 345"
What it looks like before [12 "  "  345]
What it looks like afterwards [12 "  "  345]
"12 "  "  345"
What it looks like before [  12  "  "  345]
What it looks like afterwards [12  "  "  345]
"12  "  "  345"
0
t0t0Commented:
First, I think we should concentrate on investigating how DOS itself would interpret these lines, then try to emulate that. That way, at least the batch file would produce results conducive of how the O/S handles double-quotes and that would then be definitive and final! (unless, airvector requires a customised result).


COMMAND TAIL           KNOWN                   UNKNOWN               PROCESSED
"12345"                        "12345"                                                    [12345]  
"12"345"                                                       "12"345"
"12 " 345"                                                     "12 " 345"
"12 " 345 ""                   "12", 345, nul                                           [12], [345], nul
""12 " 345"                    nul, 12, " 345"                                          nul, [12], [345]
""                                   nul                                                           nul
"" 12 " 345"                   nul, 12, " 345"                                          nul, [12], [345]
"12 "  "  345"                 "12 ", "  345"                                            [12], [345]
"12  "  "  345"                "12  ", "  345"                                           [12], [345]

As you can see, there are two entries above where (at the time of writing) there is some uncertainty.

Commas are used to show individual parameters. Square-brackets are used as delimiters showing exactly what is returned after trimming spaces.


Here's a few more that were overlooked:

COMMAND TAIL           KNOWN                   UNKNOWN               PROCESSED
"12 " 345"                                                     "12 " 345"
"12345                                                          "12345
"12 345                                                         "12 345
" 12345                                                         " 12345
12345"                                                          12345"
12 345"                                                         12 345"
12345 "                                                         12345 "
"                                                                    "
"""                                                                 """
""""                                                               """"


So, my guess is, unless we can define how these phrases should be interpreted, we're just stabbing about in the dark - and that's no basis for proper design.

What has to be decided now is: What DOS command/s do we use to guage these results?....
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
t0t0Commented:
Perhaps UNCONFIRMED is a better choice of label rather than UNKNOWN.... but I hope you know what I mean...
0
t0t0Commented:
airvector

I am still waiting for a reply to my comment (29959974)
0
t0t0Commented:
airvector

check out this fragment of code. It performs the following functions:

   (1) finds length of command tail
   (2) counts double-quotes
   (3) determines whether there are an odd or even number of double-quotes

function (3) can be really useful in deciding what course of action to take if there are mismatched double-quotes in the command tail.

One suggestion is to add a double-quote to the end of the command tail then, parse the command tail by pairing double-quotes in the order they appear working from left-to-right. That would appear to be how DOS parses the command tail.


   ::==================================================
   :: EE 25718465 - Written by Paul Tomasi 2010
   ::
   :: PARSE.BAT
   :: Parse command tail in particular, double-quotes...
   ::==================================================
   @echo off
   setlocal enabledelayedexpansion

   set string=%*

   ::-------------------------------
   :: If string is NUL, exit
   ::-------------------------------
   if not defined string (
      echo.
      echo length 0
      echo quotes 0
      exit /b 1
   )

   ::-------------------------------
   :: Get length of string
   :: Count double-quotes
   ::-------------------------------
   set ptr=0
   set quotes=0

   :loop
      if "!string:~%ptr%,1!"=="" (
         goto :end-loop
      )
     
      set character=!string:~%ptr%,1!

      if ^%character%==^" (
         set /a quotes+=1
      )
     
      set /a ptr+=1
      goto :loop
   :end-loop
   
   set length=%ptr%
   
   echo.
   echo length %length%
   echo quotes %quotes%

   ::-------------------------------
   :: Is odd or even quotes
   ::-------------------------------
   set /a sign=%quotes% %% 2
   
   if not %sign%==0 (
      echo Odd quotes
   ) else (
      if %quotes% gtr 0 (
         echo Even quotes
      ) else (
         echo No quotes present
      )
   )
   
   exit /b
   

When DOS encounters a mismatched number of double-quotes, it generally throws a dicky-fit however, there are some circumstances where DOS attempts a best-fit quess as in the following examples:

   PARSE """           <-- implies a dlimited string consisting of a single double-quote
   PARSE "abc        <-- assumes all that follows (up until the last non-space character) is a single token

in that last example, %1 would return:

   "abc

whereas, %~1 would return just:

   abc

because it is treated as if it were:

   "abc"

In conclusion. When tokenising your command tail, you're best bet would be to follow DOS's convention, then decide how to handle anything out of the ordinary as an internal preference.

your internal handling might be to apply some guesses or fuzzy logic based on the tokens that are passed and the tokens you're expecting to be passed.

as an example, suppose you're expecting ID, NAME, SOCIAL SECURITY NUMBER and CITY. Normally, you might expect something like this:

   00000001   John Doe   ab123456c   Birmingham
   00000002   Julian         de123456f    London
   etc...

now, supposing a user enters the following data string:

   00000001   "John Doe   ab123456c "Birmingham City"

as you can see, there is a mismatched number of double-quotes.

certainly, if we're passing data like "John Doe" or "Birmingham City" then we do need to delimit them using double-quotes. In this simplified (and deliberately chosen data items) it wouldn't be too difficullt to match the proper tokens to their respective data fields using minimal logic.

simply adding a double-quote onto the end of this command tail would serve no useful purpose whatsoever.

Infact, using this simple tester batch file:

   @echo off
   
   echo.
   echo 1:[%1]
   echo 1:[%~1]

   echo.
   echo 2:[%2]
   echo 2:[%~2]

   echo.
   echo 3:[%3]
   echo 3:[%~3]

   echo.
   echo 4:[%4]
   echo 4:[%~4]

we would get the following results:

   1:[00000001]
   1:[00000001]

   2:["John Doe   ab123456c "Birmingham]
   2:[John Doe   ab123456c "Birmingham]

   3:[City"]
   3:[City"]

   4:[]
   4:[]

NOTE: even though DOS parsed City" as a single token, it did NOT remove the double-quote after the letter 'y'. That's interesting. The reason for this is that DOS treats it as part of the 'data' and does not see it as a delimiter.

obviously, it's apparent to us that what is returned in %2 and %~2 is incorrect but unravelling the mess can be easy or difficult depending on what data you're expecting to arrive on the command line. This is why I asked in an earlier comment what data you're expecting.

right, I'm leaving it at that for the moment to allow you time to reply.
0
t0t0Commented:
AmazingTech

Nice to see you contribute to this question.

Hopefully you'll agree to the contents of my previous comment and seek to apply some of the information there to your treatment of the samples you've already commented on.

Taking into consideration the oder of parsing from left-to-right (as described above), what impact would this have on the results from the test data you used?

Would you agree this is the best approach?

Btw, in your code:

   if [^%string:~0,1%] == [^"]....

It is not necessary to use square-brackets if we test for a nul string beforehand. And the spaces around the equality sign '==' could be risky in some situation (I seem to remember from some time ago).
0
airvectorAuthor Commented:
Guys, I don't know what to say... Plainly, I have a command that echoes many values, and these values have quotes at f'ed up places. I want to  go through these values, and all I've been given to date is a FOR loop to use. No one knows how to pipe here, so I'm using a FOR loop, ok?

Now, I want to work on each value using the TrimLeadingAndTrailingSpaces.bat . That's why the batch file looks like what you see in the OP.

I'll provide more details briefly.
0
airvectorAuthor Commented:
So, as promised, the answers to t0t0's qtns.

are you always only expecting FOUR items to be passed as parameters?
- This I've already answered (ID: 29938529). It can be a variable-sized list of items, obtained from another command that echoes many values. Added precision here, the values can contain any type of characters, most notably spaces and quotes, along with numerical AND alphabetical values, and any other bell or carriage character you can think of.

where are these items coming from? ie, user input? read from a file? piped from another process? etc, etc...
From User Input -No
Read from a file -Maybe, is STDOUT considered a file?
piped from another process -Maybe. If catching a series of echoes from STDOUT is considered piping, but I don't think so...
etc, -Idk
etc.... -Not sure, you?

People,
To make things simple... maybe... assume a batch file that echoes hex numbers from 1010 to 1020, placing quotes and spaces at random places. Let's call it wackyhex.bat for fun. The result is a string of alphanumericals, spaces and quotes echoed to STDOUT.

idk,

10"10
" 101"1
"1012 ""
...
101A"
  1"01B "
...
"10"2" 0

Whatever, it's just an example...

Now, use a FOR loop to catch every echo from wackyhex.bat, and trim the leading and ending spaces using TrimLeadingAndTrailingSpaces.bat.

Does that make it simpler to understand? I was only using parameters to simplify my tests, like I've already described in ID: 29938529.

so far, your examples in your last comment suggest ONLY INTEGER values....
-But alas, to me it does not matter. It can be integers, characters. So long as you consider quotes and spaces differently from anything else, I'm content. Why? Because the quotes and spaces are the ones giving me problems. It's a DOS thing, you get that.
And what format will the output from 'that' command be?
-Please see example in ID: 29958928 and examples above.
0
AmazingTechCommented:
Does ID: 29985617 work for you?
0
airvectorAuthor Commented:
AT, it most definitely works. Haven't tried the for loop part yet. So, I've combined your code with t0t0's code, and I got what you see attached. Qtn, how did you reduce this
:leadingif "!string:~0,1!" == " " (  set string=!string:~1!  goto leading) echo to trailing :trailingif "!string:~-1!" == " " (  set string=!string:~0,-1!  goto trailing)

------------------------------------------------
To this:
-------------------------------------------------

  CALL :TRIM %string%  GOTO :EOF    :TRIM  set string=%*
0
airvectorAuthor Commented:
Sorry, code for prev post attached here. (Rich text thing made the attachment dissappear)
@ECHO off
  set string=%*  
  echo What it looks like before [%string%]
  
  if not defined string goto :return
  if ^%string:~0,1%==^" if ^%string:~-1%==^" set string=%string:~1,-1%
  if not defined string goto :return

  CALL :TRIM %string%
  GOTO :EOF
  
  :TRIM
  set string=%*
  
  :RETURN
  echo What it looks like afterwards [%string%]
  echo "%string%"

Open in new window

0
AmazingTechCommented:
The call :Label is the same as using call Batchfile.bat.

And instead of getting each individual parameter with %1 %2... I used %* to take the entire input as 1 parameter. Being 1 parameter it trims all leading and trailing spaces even if there were 1 or more spaces.

The old number of quotes makes it difficult in using a FOR LOOP. It can be done we would need to change the quotes to something else temporarily and then back to quotes.

We could do it this way too.
@ECHO off
  set string=%*
  if [^%string:~0,1%] == [^"] set string=%string:~1%
  if [^%string:~-1%] == [^"] set string=%string:~0,-1%

  echo What it looks like before [%string%]

  CALL :TRIM %string%
  echo What it looks like afterwards [%string%]
  echo "%string%"
  GOTO :EOF 
  :TRIM
  set string=%*
  GOTO :EOF

Open in new window

0
AmazingTechCommented:
Actually, I wouldn't do it this way. This only fixes the quotes if beginning and ending. You example input
"  12  "  "  345

Would not remove the first quotes thus not triming the space before 12 unless that's what you wanted.

if ^%string:~0,1%==^" set string=%string:~1%
if ^%string:~-1%==^" set string=%string:~0,-1%

Which is essentially the same as mine with the brackets. I used the bracket for ease of understanding.
0
Bill PrewCommented:
This thread sure has wandered around a bit, and covered a lot of ground...

If you are also going to include other special characters like |, <, >, ^, etc in your input strings I think you will find that parsing and manipulating these in a BAT file will be a challenge.  You also mention "bell and carraige" characters which to me imply "binary" characters, like a line feed, or a tab.  These will also be particularly problematic in a BAT file.

I would post further since I believe I had a good bit of the solution in 29950728 but it still isn't quite clear to me exactly what the comain of input is, and what the needed output of the "parsing" and "trimming" needs to be.  But I may be slower than most...

~bp

~bp
0
airvectorAuthor Commented:
billprew, I don't think it's a qtn of being slow, it seems to me that this has turned out to be alot more challenging that it first appeared, not only to solve, but also to understand. The question is so open and the vast scenarios that may exist bears the question of whether it is even plausible to be handled in BAT files, as you suggested. Though the "bell and carriage" characters thing was a pun, I think you got the gist of it.

You know, the idea is that I'm trying to get around the behavior of DOS, whereby it'll fail at a quote mismatch or at the appearance of an unexpected character. Take the backquote for example. What if my string contains quotes and a backquote, and it is passed to a call inside a for loop. I tried it, and it just doesn't run the script. I'll provide the example if you guys want it.

t0t0, as you said,
this is NOT a competition. We are experts who (in my case) enjoy solving problems using batch programming.
I for one have enjoyed the complexity and insight of this thread. (It's no wonder the replies keep popping in, I can barely keep up). Just remember that the onus will be on me at the end to properly assign points to those who've helped. For now, the TrimLeadingAndTrailingSpaces.bat script I came up with in ID: 30042968 was contributed by t0t0, billprew and AmazingTech, for now.

As for the FOR loop issue, I think I'll accept the solutions of those who've helped me come to a satisfying understanding of how DOS struggles with awkward values, what the problematic scenarios are (generally), and why the code in the OP fails, given the new version of TrimLeadingAndTrailingSpaces.bat . So, I suggest we continue where t0t0 left off on ID: 29990787. I personally am getting through ID: 30001694 as it is.
0
airvectorAuthor Commented:
And, don't forget to REM the debug lines in TrimLeadingAndTrailingSpaces.bat when testing against the FOR loop. Just echo one output, that is, "%string%", at the end.
0
t0t0Commented:
airvector

PLEASE READ THE FOLLOWING COMMENT VERY CAREFULLY.

UNLESS you can answer the following question satisfatorily, I will decline to contribute further to this thread.

--------------------------------------------------------------------------------------------
QUESTION

In your opening statement, you write:

   ...there is an input that is problematic for me.

   Pass it " 12 "1" 23 "", and the function will fail.

The function you refer to is TrimLeadingAndTrailingSpaces.bat.

Therefore, given the following command tail

   " 12 "1" 23 ""

(Now, please think about this one VERY CAREFULLY!) Imagine for a moment it was YOU who had entered this as input on the command line. Looking back at this input now and realising you had made a mistake, WHAT SHOULD have entered instead (or in other word, WHAT did you INTEND to enter)?

The following is an example of how you might answer this question. You might reply with something along the following lines:

I INTENDED to enter:

    the number 12 in double-quotes followed by,
    "1" as it appears followed by,
    the number 23 followed by,
    a null (empty) string (denoted by "")

Of course, that's just ONE of many plausible interpretations....

I want to know what YOUR interpretation is of the command tail is based on what you might of INTENDED to enter had it been you who had entered it in the first place.
--------------------------------------------------------------------------------------------

NOW, PLEASE ANSWER THE QUESTION
0
airvectorAuthor Commented:
Two words: COPY, PASTE, was my initial answer.

But I gave your comment a little more thought, and I think it was the right thing to do. May I reword your question?

What do you expect someone careful to enter?

The answer is, and always has been: anything. I don't expect the user to be careful, and the user may not even be human. It may be some other batch file that reads every line from a file and calls TrimLeadingAndTrailingSpaces.bat on each line.

I know this may seem ludicrous: why trim spaces on something that's already f'ed up? But the point of using TrimLeadingAndTrailingSpaces.bat rather than anything else, is because it was one of the best scripts I had to handle tricky input (I spent 500 points on it alone already). I may want to do more complex operations on each line in the future, such as search for a specific pattern, but I wanted to start with something simple. Go figure!

Now I hope you understand where I'm coming from.
0
AmazingTechCommented:
It's a valid question and takes some investigation and understanding of what is going on. At the onset I'm sure it looked as though it was an easy request.

But upon numerous examinations by various experts it was difficult to figure out the true intended output.

Sorry, I don't usually put much detail/comments in the code I'm writing simply because I usually start from scratch for each question. This helps me in remembering the correct syntax. Also why bother with all the comments if the code does not satisfy the question being asked. I'm more than happy to explain what's going on or what I did or why I've done certain things after.

I hope you have arrived at a solution. Let us know if you need any more explaination.

In the end the tricky part of this question was the miss match number of double quotes and how it is handled at input parameters and how for loop fails. Using labels and %* we get around these 2 problems.
0
airvectorAuthor Commented:
As a sample script to run the for loop on, you can use this:
@echo off
echo hello my name is "John". I want to use function `dir /b` sometime in the future.
echo.
echo hi! My name is not ^, it's " Jane ". I have a question about using " " or "" in dos.
echo I want to ask it to the people on E-E, but
echo... with all these wierd characters like !@#$%^&*()[]éà / and ding dong! I don't know if I'll ever be able to
echo   what I wanted to do in the first place. "  -- 'Jane

Open in new window

0
airvectorAuthor Commented:
Call that code in ID 30136426 story.bat and run it in the following code. I can't make it simpler than that I'm afraid. Simple than what you see below and the question doesn't exist anymore, sorry.
@echo off
FOR /F "usebackq" %%a IN (`story.bat`) DO echo %%a

Open in new window

0
AmazingTechCommented:
How about?
@echo off
FOR /F "usebackq tokens=*" %%a IN (`story.bat`) DO echo %%a

Open in new window

0
airvectorAuthor Commented:
ok, now we're getting somewhere.

 ID: 30137629 works better than ID: 30136870 with a single FOR loop. Now let's try

@echo off
FOR /F "usebackq tokens=*" %%a IN (`story.bat`) DO (
  echo story.bat:  %%a
  for /F "usebackq tokens=*" %%s in (`AMCore.TrimLeadingAndTrailingSpaces.callscript.bat %%a`) do echo trim.bat:  %%s
)

Open in new window

0
airvectorAuthor Commented:
I get this. I think we're almost there!
story.bat:  hello my name is "John". I want to use function `dir /b` sometime in t
he future.
trim.bat:  "hello my name is "John". I want to use function `dir /b` sometime in t
he future."
story.bat:  hi! My name is not , it's " Jane ". I have a question about using " "
or "" in dos.
trim.bat:  "hi! My name is not , it's " Jane ". I have a question about using " "
or "" in dos."
story.bat:  I want to ask it to the people on E-E, but
trim.bat:  "I want to ask it to the people on E-E, but"
story.bat:  .. with all these wierd characters like !@#$&*()[]Ta / and ding dong!
I don't know if I'll ever be able to do
'*' is not recognized as an internal or external command,
operable program or batch file.
trim.bat:  ".. with all these wierd characters like !@#$"
story.bat:  what I wanted to do in the first place. "  -- 'Jane
trim.bat:  "what I wanted to do in the first place. "  -- 'Jane"

Open in new window

0
AmazingTechCommented:
Problem occurs with the & it thinks you want to do another command. Try adding in the quotes.

I'm going to change the %%a to "%%~a". In theory it's the same for variable already with the quotes. I'm just forcing to make sure the quotes exist. But we might get into a problem with uneven quotes.
@echo off
FOR /F "usebackq tokens=*" %%a IN (`story.bat`) DO (
  echo story.bat:  %%a
  for /F "usebackq tokens=*" %%s in (`AMCore.TrimLeadingAndTrailingSpaces.callscript.bat "%%~a"`) do echo trim.bat:  %%s
)

Open in new window

0
airvectorAuthor Commented:
I moved the &, and placed it between ding and dong in case the * had anything to do with it. I now get.
'dong!' is not recognized as an internal or external command,
operable program or batch file.
story.bat:  hello my name is "John". I want to use function `dir /b` sometime in t
he future.
trim.bat:  ""hello my name is "John". I want to use function `dir /b` sometime in
the future.""
story.bat:  hi! My name is not , it's " Jane ". I have a question about using " "
or "" in dos.
trim.bat:  ""hi! My name is not , it's " Jane ". I have a question about using " "
 or "" in dos.""
story.bat:  I want to ask it to the people on E-E, but
trim.bat:  ""I want to ask it to the people on E-E, but""
story.bat:  .. with all these wierd characters like !@#$*()[]Ta / and ding
trim.bat:  "".. with all these wierd characters like !@#$*()[]Ta / and ding ""
story.bat:  what I wanted to do in the first place. "  -- 'Jane
trim.bat:  ""what I wanted to do in the first place. "  -- 'Jane""

Open in new window

0
airvectorAuthor Commented:
Above, I also did what was said in ID: 30139593, replaced %%a to "%%~a" in call to trimbla.bat.
0
airvectorAuthor Commented:
0
airvectorAuthor Commented:
Finally having taken the time to read ID: 30001694.

The well designed example was

00000001   "John Doe   ab123456c "Birmingham City"

certainly, if we're passing data like "John Doe" or "Birmingham City" then we do need to delimit them using double-quotes. In this simplified (and deliberately chosen data items) it wouldn't be too difficullt to match the proper tokens to their respective data fields using minimal logic.

simply adding a double-quote onto the end of this command tail would  serve no useful purpose whatsoever.
True. It could be decided in advanced how long a column is, and ensure proper escaping or quote-matching within that size. For example, I could handle this as follows:


0         1         2         3         4         5          6         7         8
01234567890123456789012345678901234567890123456789001234567890123456789001234567890

00000001            "John Doe         " ab123456c            "Birmingham City"

Open in new window

0
airvectorAuthor Commented:
Now, what if a user submits

00000001   John "J" Doe   ab123456c "Birmingham City"

How would you handle that when expecting 4 values? Maybe apply the size rule again like this?.
0         1         2         3         4         5          6         7         8
01234567890123456789012345678901234567890123456789001234567890123456789001234567890

00000001            "John "J" Doe     " ab123456c            "Birmingham City"

Open in new window

0
airvectorAuthor Commented:
Keep in mind that the rabbit trail I've been following since ID: 30141572 is in response to ID: 30001694 for the sake of understanding and discussion. It is a case where we expect 4 values.

But for the sake of solving the problem in OP, please continue on the trail started as of ID: 30137629.
0
airvectorAuthor Commented:
Goal: escaping the ampersands

Let's say I create a batch file to escape every '&' in a string echoed to STDOUT. I would call that file escapeAmpersands.bat.

Calling it within a FOR loop seems to be a catch 22.

@echo off
FOR /F "usebackq tokens=*" %%a IN (`story.bat`) DO (
  echo story.bat:  %%a
  for /F "usebackq tokens=*" %%s in (`escapeAmpersands.bat %%~a`) do echo escapeAmpersands.bat:  %%s
)

Anyway, I created a batch to count ampersands based on the count quotes from ID: 30001694. It works when I call it off the command line, but not in the FOR loop, probably due to what AmazingTech described.

@echo off
   setlocal enabledelayedexpansion

   set string=%*   

   ::-------------------------------
   :: Get length of string
   :: Count ampers
   ::-------------------------------
   set ptr=0
   set ampers=0

   :loop
      if "!string:~%ptr%,1!"=="" (
         goto :end-loop
      )
     
      set character=!string:~%ptr%,1!

      if ^%character%==^& (
         set /a ampers+=1
      )
     
      set /a ptr+=1
      goto :loop
   :end-loop
   
   set length=%ptr%
   
   echo.
   echo length %length%
   echo ampers %ampers%

   exit /b

Open in new window

0
airvectorAuthor Commented:
Has anyone heard of sed for windows?

The one thing I don't like about it is that it follows the GPL. I mean, I support the GPL, but when you want to have things that belong to you, it's less cool.

I'm starting to thing of doing this stuff in another language like ruby or python and making a call to the executable for output. I'm currently using grep, and the guys were able to make it a pipeable command.

Here is a sample line of code from one of my files:


for /F "usebackq" %%m IN (`echo %dSwtVal% ^| grep -E -o -i "^[[:space:]]*(left)|(right)[[:space:]]*$" ^| grep -E -o -i "(left)|(right)"`) do SET %dSwtVal%=%%m

Open in new window

0
AmazingTechCommented:
I think there is SED for windows it's been a long time but I haven't used it. Working with the ampersand is troublesome in DOS. I've been trying to make things work but you might want to change the trim back to what t0t0 suggested if the ampersand is going to be used.

You can escape the ampersand with

Set string=%string:&=^&%
0
airvectorAuthor Commented:
For those still interested,
I'm working on the second part of the question on my end.  I will post when I have sufficiently understood the way DOS deals with arguments in Call statements, For loop commands and regular batch calls, as well as the various contexts (calling from prompt or calling from within another script), and the various ways of getting argument values (getting all characters with %* or getting args one at a time with shift) and for each case, how to deal with irregular input in a way that is compatible with the other cases. If I don't find a solution, at least I'll post my findings. And if I don't have the energy to do that, I'll close the topic and assign points appropriately.

Thanks for your patience,
airvector
0
airvectorAuthor Commented:
Guys, I'm closing it here. Please look at my last comment and at the comment marked as best solution to further investigate this question.

Thanks to all who've helped!

airvector
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft DOS

From novice to tech pro — start learning today.