A different method to trim spaces from a string

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

A different method to trim spaces from a string

#1 Post by Aacini » 01 Apr 2012 20:55

I wrote this after read aGerman's Macro $RTrim and dbenham's Novel method to right trim. I think this subject is interesting, so I developed my own version.

I used a different method to both left and right trim based on the fact that subroutine parameters are comprised of group of characters separated by spaces, so multiple spaces before the first parameter or after the last one are ignored by them. This way, I get the first character of the first parameter and the last character of the last parameter and use they to delimit the original string. Here it is:

Code: Select all

@echo off
setlocal DisableDelayedExpansion
set "string=      qwerty    uiop    ^carets^    %%percents%%    end     "
setlocal EnableDelayedExpansion
echo Original: [!string!]
call :TrimSpaces string
echo Trimmed:  [!string!]
goto :EOF


:TrimSpaces strVar -- Trim spaces from strVar
if not defined %1 exit /b
setlocal EnableDelayedExpansion
set "var=!%1!"
call :getBounds !var:%%=%%%%!
rem Left trim:
set "var=!var:*%firstChar%=%firstChar%!"
rem Right trim:
if "!var:~-1!" neq " " goto rightTrimmed
set "var=!var:%lastParam% =%lastParam%þ !"
:catNext
   for /F "tokens=1,2* delims=þ" %%a in ("!var!") do (
      set "var=%%a"
      set "mid=%%b"
      set "rest=%%c"
   )
if defined rest set "var=!var!!mid!þ!rest!"& goto catNext
:rightTrimmed
endlocal & set "%1=%var%"
exit /B


:getBounds
setlocal DisableDelayedExpansion
set "firstParam=%1"
:getlastParam
   set "lastParam=%1"
   shift
if "%1" neq "" goto getlastParam
endlocal & set "firstChar=%firstParam:~0,1%"& set "lastParam=%lastParam%"
exit /B

This first version of this code have the same common problems with special characters, that may or may not be solved in the usual ways.

EDIT: I slightly modified the code to process as delimiter the entire last parameter instead of just its last character; this avoid to process several words that may have the same last character than the last word. If the last word is unique, right trim consist in two steps: get the last parameter and trim the spaces after it. If there are several words equal to the last one, then a loop is required to process each one and trim spaces after the last one. Left trim is always a two step process: get the first character and trim the spaces before it.

Antonio

Samir
Posts: 357
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: A different method to trim spaces from a string

#2 Post by Samir » 16 Jul 2013 12:20

I found a really quick and dirty way to trim spaces from a for variable by using %~nF. Even though ~n is reserved for filenames, it does a great job of stripping out white space. :D

probyn
Posts: 7
Joined: 23 May 2013 20:01

Re: A different method to trim spaces from a string

#3 Post by probyn » 16 Jul 2013 13:19

Samir wrote:I found a really quick and dirty way to trim spaces from a for variable by using %~nF. Even though ~n is reserved for filenames, it does a great job of stripping out white space. :D


This one-liner will take care of both left and right trimming of spaces: ;-)
----------begin screen capture---------
C:\CMD>set mystring=abcde

C:\CMD>echo/[%mystring%]
[abcde ]

C:\CMD>demo\trim %mystring%

C:\CMD>echo [%trim%]
[abcde]

C:\CMD>set mystring= abcde

C:\CMD>echo/[%mystring%]
[ abcde]

C:\CMD>demo\trim %mystring%

C:\CMD>echo [%trim%]
[abcde]

C:\CMD>type demo\trim.cmd
@set %~n0=%*

C:\CMD>set mystring= abcde

C:\CMD>echo/[%mystring%]
[ abcde ]

C:\CMD>demo\trim %mystring%

C:\CMD>echo [%trim%]
[abcde]
----------end screen capture---------

Phil Robyn
udetodyelekrebtanyborp

Samir
Posts: 357
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: A different method to trim spaces from a string

#4 Post by Samir » 16 Jul 2013 14:41

probyn wrote:
Samir wrote:I found a really quick and dirty way to trim spaces from a for variable by using %~nF. Even though ~n is reserved for filenames, it does a great job of stripping out white space. :D


This one-liner will take care of both left and right trimming of spaces: ;-)
----------begin screen capture---------
C:\CMD>set mystring=abcde

C:\CMD>echo/[%mystring%]
[abcde ]

C:\CMD>demo\trim %mystring%

C:\CMD>echo [%trim%]
[abcde]

C:\CMD>set mystring= abcde

C:\CMD>echo/[%mystring%]
[ abcde]

C:\CMD>demo\trim %mystring%

C:\CMD>echo [%trim%]
[abcde]

C:\CMD>type demo\trim.cmd
@set %~n0=%*

C:\CMD>set mystring= abcde

C:\CMD>echo/[%mystring%]
[ abcde ]

C:\CMD>demo\trim %mystring%

C:\CMD>echo [%trim%]
[abcde]
----------end screen capture---------

Phil Robyn
udetodyelekrebtanyborp
Pretty neat, but where are you getting the trim command from?

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

Re: A different method to trim spaces from a string

#5 Post by penpen » 16 Jul 2013 15:02

@Samir
It seems to right trim only:

Code: Select all

Z:\>for %f in ("   test test test         ") do echo "%~nf"
"   test test test"

@probyn
This woorks very good, but is unsafe:

Code: Select all

trim   asdad       asd   ^& echo Leak
Maybe i am a little bit too mistrustful, but this is my maxime on external input.

penpen

Edit: Testet on WinXP home with all patches up to now.

probyn
Posts: 7
Joined: 23 May 2013 20:01

Re: A different method to trim spaces from a string

#6 Post by probyn » 16 Jul 2013 16:36

penpen wrote:@Samir
It seems to right trim only:

Code: Select all

Z:\>for %f in ("   test test test         ") do echo "%~nf"
"   test test test"

@probyn
This woorks very good, but is unsafe:

Code: Select all

trim   asdad       asd   ^& echo Leak
Maybe i am a little bit too mistrustful, but this is my maxime on external input.

penpen

Edit: Testet on WinXP home with all patches up to now.


Is it any safer if we just pass the name of the variable whose value is to be trimmed rather than the value itself?

--------begin screen capture WinXP in WinVPC on Win7 Pro---------
C:\CMD>set mystring= abcdefg

C:\CMD>echo/[%mystring%]
[ abcdefg ]

C:\CMD>safetrim mystring

C:\CMD>echo/[%mystring%]
[abcdefg]

C:\CMD>inpath safetrim .
c:\CMD\TEST\safetrim.cmd

C:\CMD>wlist %*%
≡≡≡begin c:\CMD\TEST\safetrim.cmd≡≡≡
1. @echo off
2. set x=%1
3. for /f "tokens=1* delims==" %%a in (
4. 'set %1'
5. ) do call :exec %%b
6. goto :EOF
7. :exec
8. set %x%=%*
9. goto :EOF
≡≡≡end c:\CMD\TEST\safetrim.cmd≡≡≡
--------end screen capture WinXP in WinVPC on Win7 Pro---------

Phil Robyn

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

Re: A different method to trim spaces from a string

#7 Post by penpen » 16 Jul 2013 18:27

probyn wrote:Is it any safer if we just pass the name of the variable whose value is to be trimmed rather than the value itself?
Much better, i have tested all tricks, i remembered, on your safetrim.bat:

Code: Select all

@echo off
set x=%1
for /f "tokens=1* delims==" %%a in (
'set %1'
do call :exec %%b
goto :EOF
:exec
set %x%=%*
goto :EOF
I could not execute my code from outer batch file.

The best i have managed to do is, to make the interpreter believe the next line to execute is line 10, but this is not of much use.
You can make it visible by appending an echo Echo. line to the end of safeTrim.bat:

Code: Select all

Z:\>set TEST=    test  ^^        

Z:\>safeTrim TEST
Echo.

Z:\>
But this behaviour can be avoided easily by inserting 2 empty lines between line 8 and 9.

I like it,
penpen

foxidrive
Expert
Posts: 6033
Joined: 10 Feb 2012 02:20

Re: A different method to trim spaces from a string

#8 Post by foxidrive » 16 Jul 2013 18:48

That's quite neat. This works pretty well too but slashes will confound it.

Code: Select all

@echo off
set "text=  test & ^^ & .   def   "
for %%a in ("%text%") do for /f "tokens=*" %%b in ("%%~nxa") do echo "%%b"



Code: Select all

"test & ^^ & .   def"

Samir
Posts: 357
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: A different method to trim spaces from a string

#9 Post by Samir » 16 Jul 2013 22:37

penpen wrote:@Samir
It seems to right trim only:

Code: Select all

Z:\>for %f in ("   test test test         ") do echo "%~nf"
"   test test test"

@probyn
This woorks very good, but is unsafe:

Code: Select all

trim   asdad       asd   ^& echo Leak
Maybe i am a little bit too mistrustful, but this is my maxime on external input.

penpen

Edit: Testet on WinXP home with all patches up to now.
Ahh...good call. I think I saw that too, but didn't think too much about it when one of my strings had a space prefacing it. :(

I wonder if the related function %~xf will trim the left. :?:

foxidrive
Expert
Posts: 6033
Joined: 10 Feb 2012 02:20

Re: A different method to trim spaces from a string

#10 Post by foxidrive » 17 Jul 2013 00:01

Using %~nf without %~nxf will make periods a poison character and seriously limit the usefulness of the exploit.

As I illustrated in my code above, %~nxa works well.

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

Re: A different method to trim spaces from a string

#11 Post by penpen » 17 Jul 2013 00:55

@probyn
I've found an issue when executing:

Code: Select all

Z:\>SET TEST=   test   

Z:\>SET TEST_A=   test a   

Z:\>safeTrim TEST

Z:\>SET TEST
TEST=test a
TEST_A=   test a   

This could be fixed by adding a safe if "%1" == "TEST", also a %1 gatekeeper should be performed, so the whole code changes to:

Code: Select all

@echo off
setlocal enableDelayedExpansion
set x=%1
if not defined x exit /b 1

for /f "tokens=1* delims==" %%a in (
'set %1'
) do (
set call _TMP=%%x:%%a=%%
if not defined _TMP endlocal & call :exec %%b
)
goto :EOF
:exec
set %x%=%*


goto :EOF
Btw: I only talked about safeness, because the batch may be run from students (in my case) that wanted to gain more privileges. They executed such an unsafe batch and made themselfes to local admins (as our admin, who installed this batch made the system to compute it with admin rights... and i had to find out who, and how they have done it... ... ... NOT funny). Since then i am mistrusting any external data that are passed to batch files.

@Samir
Additionally %~nf will shorten " test & ^^ & . def " to " test & ^^ &",
and %~xf will shorten this string to ". def ".
EDIT: foxidrive was faster. :D

@foxidrive
foxidrive wrote:but slashes will confound it
Double quotes, too.
Nevertheless it is a pretty nice trim function as you could replace all problematic characters with other ones prior to use it.

penpen

Edit: Students of computer science that wanted to play games on the computers in the cip pool.
Last edited by penpen on 17 Jul 2013 04:58, edited 1 time in total.

foxidrive
Expert
Posts: 6033
Joined: 10 Feb 2012 02:20

Re: A different method to trim spaces from a string

#12 Post by foxidrive » 17 Jul 2013 01:47

Yes, that was a good find Samir.

alan_b
Expert
Posts: 357
Joined: 04 Oct 2008 09:49

Re: A different method to trim spaces from a string

#13 Post by alan_b » 17 Jul 2013 03:34

penpen wrote:Btw: I only talked about safeness, because the batch may be run from students (in my case) that wanted to gain more privileges. They executed such an unsafe batch and made themselfes to local admins (as our admin, who installed this batch made the system to compute it with admin rights... and i had to find out who, and how they have done it... ... ... NOT funny). Since then i am mustrusting any external data that are passed to batch files.

At first I thought your speciality was computer forensics, and the focus on safety a little extreme,
but now I can see the need for paranoia when trying to protect your systems from students with potential as system administrators or hackers.
You have my respect

Regards
Alan

dbenham
Expert
Posts: 2369
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: A different method to trim spaces from a string

#14 Post by dbenham » 17 Jul 2013 05:54

The %%~nF technique is the basis of the the solution I posted that Aacini originally cited at the top of this thread: Novel method to right trim.

I actually use %%~nxF, and I add some extra code to preserve : . / \ * ? as well as all the standard poison characters. I believe it is a safe routine.

I suppose discussion about the %%~nxF technique is better placed at my post :wink:

Back to the original subject of this thread :roll: Aacini's proposed method for trimming has problems when there are quotes within the string.

As written, it exposes poison characters if they are quoted within the string, and it fails entirely if there are unbalanced quotes in the string. I imagine that problem can be fixed by replacing the quotes with a protective character combination before trimming, and then restoring the quotes when finished.


Dave Benham

Samir
Posts: 357
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: A different method to trim spaces from a string

#15 Post by Samir » 17 Jul 2013 10:57

foxidrive wrote:Using %~nf without %~nxf will make periods a poison character and seriously limit the usefulness of the exploit.

As I illustrated in my code above, %~nxa works well.

penpen wrote:@Samir
Additionally %~nf will shorten " test & ^^ & . def " to " test & ^^ &",
and %~xf will shorten this string to ". def ".
EDIT: foxidrive was faster. :D
Yes, but you explained it more. :D Thank you both for testing this! I'll update my code to use %~nxF. 8)
foxidrive wrote:Yes, that was a good find Samir.
You guys perfected it. 8)
dbenham wrote:The %%~nF technique is the basis of the the solution I posted that Aacini originally cited at the top of this thread: Novel method to right trim.
I should have searched for this. :oops: Awesome find though, and a BIG thank you for detailing all the caveats of the method. 8) Now, I know what I need to specifically look for without having to test forever.

Post Reply