Hello world ! a special char > catch, process and echo

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Hello world ! a special char > catch, process and echo

#1 Post by Ed Dyreen » 29 Nov 2011 07:44

'
I was wondering if there is a consistent way of making sure special chars get through functions as intended. I am making progress, but I'm disappointed. It seems special chars need to be escaped whenever they appear in a for.

Code: Select all

@echo off &setlocal disableDelayedExpansion

   setlocal enableDelayedExpansion
   :: (
      <"%~0" >nul (set /p $lf=&pause&set /p $lf=)
   :: )
   for %%r in ( "!$lf:~0,1!" ) do endlocal &set "$lf=%%~r" &echo. &echo.This%%~rworks

   set ^"$n1c=^^^%$lf%%$lf%^%$lf%%$lf%^^"

:: part of interest

   set    ^"forX_=set "$NotDelayedFlag=!" ^&setlocal enableDelayedExpansion ^&set "$=" ^&( for %%^! in"
   set ^"_Udelim_=do set "$=!$!¦%%!" ) ^&( %$n1c%
      set "$=!$:*¦=!" ^&set "$=!$:~1,-1!" ^&if not defined $NotDelayedFlag ( %$n1c%
         set ^"$=!$:^"=###q!^" %$n1c%
         set  "$=!$:^=^^!" %=                     replace directly =% %$n1c%
         call set "$=%%^$:^!=""^!%%" ! %$n1c%
         set  "$=!$:""=^!" %$n1c%
         set ^"$=!$:###q=^"!^" %$n1c%
      ) %$n1c%
   ) ^&for /f "tokens=1-26 delims=¦" %%a in ( "!$!" ) do ( endlocal ^&"

:: part of testing

   setlocal disableDelayedExpansion
   :: (
      %forX_% ( '$debug, "This ^^^^Works ^^^!"' ) %_Udelim_% echo. a=%%a_ &echo. b=%%b_ )
   :: )
   endlocal

   setlocal enableDelayedExpansion
   :: (
      %forX_% ( '$debug, "This ^^^^Works ^^^!"' ) %_Udelim_% echo. a=%%a_ &echo. b=%%b_ )
   :: )
   endlocal

pause
exit
tested ok, expected result delayed insensitive:

Code: Select all

a=$debug_
b=This ^Works !

a=$debug_
b=This ^Works !
All I wanted to do was to make functions independent of the current delay state, and then this popped up, I knew about this issue, but avoided it until now. since I use for continuously this is quite painful. :cry:

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

Re: Hello world ! a special char

#2 Post by jeb » 30 Nov 2011 00:38

Hi tooComplex,

I can only guess what your question could be :)

Can you explain why you use just the exclamation mark of all charactes?
The only character (and the caret) that is affected by the delayed expansion :!:

You really earned the title tooComplex :D

jeb

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Hello world ! a special char

#3 Post by Ed Dyreen » 30 Nov 2011 10:41

:lol:
It is a good joke, one always starts simple and when the moment of implementation arrives, one is overwhelmed by how complex a seemingly easy problem can get. Wondering if one is on the right path...

Lets say we pass a parameter with a for. like "hello world ^^^!".
Independent of the current delay state we already have to escape !, to make sure it can be accessed inside for ( assuming we enable delayed immediately ).
Now imagine our function/macro/for loop wants to pass this value to another for, now the escaping has to be done all over again, this is true for every for used inside for.
Passing a value by reference solves this but one can always imagine a case where passing by value is desirable.
Having functions who are insensitive to the current delay state ads robustness and flexibility.

This becomes a problem quickly when we work with macros who are limited in the amount of code they can contain.
I am very grateful to your recent post, which explains that we can externalize macros by running them in their own for in ( CMD ) clausule. And then process the output with for just as we would with any other external command :D
I am currently applying and testing this technique, which I may post about if the results are encouraging.

Didn't I ask a question, oops... :roll:
I wonder if the above code is efficient for achieving this goal. There must be a better way, a simpler way, this is tooComplex.
At the testing part the intention is that regardless of the delayed state a user will be able to pass parameters in an always the same manner, that they are split into tokens and are always received, processed and returned as intended.

ps: As you can see I didn't use your appending technique, I don't think it would make any difference and I just can't keep up, which is good !

Code: Select all

@echo off

for %%! in ( "hello ^^there ^!" ) do echo.%%!
setlocal enableDelayedExpansion
for %%! in ( "hello ^^there ^!" ) do echo.%%!
endlocal

pause
exit

Code: Select all

"hello ^^there ^!"
"hello there "
Interesting, it seems that escaping may not even be required if I catch the parameter with delayed disabled. That's great... ...
Now it's beginning to dawn me, why dBenham X disable delayed.
But now it's a problem to split the tokens grrr... :evil: do set "$=!$!¦%%!" )

You may wonder why I don't just split the tokens immediately within the first for.
This has everything to do with XP's FOR /F bug that comes in effect if there are unescaped or unquoted delimiters in the input.

Really the only thing I try to achieve here is adding support for special chars without forcing the user into having to encode the input. A simplification may seem obviously :)

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Hello world ! a special char

#4 Post by Ed Dyreen » 30 Nov 2011 16:40

'
Never mind jeb, I figured it out, and I'll stop here because talking to myself looks kinda silly:

Code: Select all

:skip ()
:: --------------------------------------------------------------------------------------------------------------------------
%Pre_% forX_, _Udelim_
:: --------------------------------------------------------------------------------------------------------------------------
:: last updated       : 30/11/2011
:: support            : NAdelayed, style AutoIT, avoids the XP FOR /F: 'Kan bestand Ãüé??ú®?? niet vinden.' bug
::
:: Use this as alphanumeric token that splits on <space> and <TAB>, only for macros that start with _Udelim_ !
:: (
%   % set    ^"forX_=set "$NotDelayedFlag=!" ^&setlocal disableDelayedExpansion ^&set "$=" ^&( for %%^! in"
%   % set ^"_Udelim_=do set "?=%%!" ^&setlocal enableDelayedExpansion ^&( %$n1c%
%      % set "$=!$!¦!?!" ^&for /f "delims=" %%? in ( "!$!" ) do endlocal ^&set "$=%%~?" ) %$n1c%
%   % ) ^&( %$n1c%
%      % setlocal enableDelayedExpansion ^&set "$=!$:~2,-1!" %$n1c%
%   % ) ^&for /f "tokens=1-26 delims=¦" %%a in ( "!$!" ) do endlocal ^&endlocal ^&"
:: )
%Post_% forX_, _Udelim_ [OK]
::
setlocal disableDelayedExpansion
:: (
   set "$var=This ^Works !"
   setlocal disableDelayedExpansion
   :: (
      %forX_% ( '$var, "!$var!", "This ^^Works ^!", "This ^^Works ^!"' ) %_Udelim_% setlocal enableDelayedExpansion &%@n2echo_% a=%%a=!%%~a!_ &%@necho_% b=%%b=!%%~b!_ &%@necho_% c=%%c=!%%~c!_ &%@necho_% d=%%d=!%%~d!_ &endlocal
   :: )
   endlocal

   setlocal enableDelayedExpansion
   :: (
      %forX_% ( '$var, "!$var!", "This ^^Works ^!", "This ^^Works ^!"' ) %_Udelim_% setlocal enableDelayedExpansion &%@n2echo_% a=%%a=!%%~a!_ &%@necho_% b=%%b=!%%~b!_ &%@necho_% c=%%c=!%%~c!_ &%@necho_% d=%%d=!%%~d!_ &endlocal
   :: )
   endlocal
:: )
endlocal
::
>> "succes.log" echo.forX_-Udelim
:: --------------------------------------------------------------------------------------------------------------------------
::goto :skip "()"
%@endoftest%
:skip ()

Code: Select all

 >> forX_, _Udelim_
 << forX_, _Udelim_ [OK]

 a=$var=This ^Works !_
 b="This ^Works !"=This ^Works !_
 c="This ^Works !"=_
 d="This ^Works !"=_

 a=$var=This ^Works !_
 b="This ^Works !"=This ^Works !_
 c="This ^Works !"=_
 d="This ^Works !"=_
 endoftest Druk op een toets om door te gaan. . .
So the trick is in disable delayed. I was apparently creating an elephant out of a mouse.

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

Re: [solved] Hello world ! a special char

#5 Post by jeb » 01 Dec 2011 06:34

Ed Dyreen wrote:Never mind jeb, I figured it out, and I'll stop here because talking to myself looks kinda silly:


I read this thread too, but your solution doesn't look nice :wink:

I would prefere something like

Code: Select all

@echo off
cls
setlocal DisableDelayedExpansion
call :LoadMacros

setlocal EnableDelayedExpansion
%MagicEcho% This works! Even with a single caret^, but how? %MagicEnd%
%MagicEcho% Ampersand & and pipe | works also in quotes " & | ! ^ "%MagicEnd%
echo This fails! Even a single caret^ fails

echo(
setlocal DisableDelayedExpansion
%MagicEcho% This works! Even with a single caret^, but how? %MagicEnd%

echo This works! Even a single caret^ fails
exit /b


The macros are obvious, and can be made by the reader in 5 minutes of homework :D

jeb

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: [solved] Hello world ! a special char

#6 Post by Ed Dyreen » 01 Dec 2011 12:41

'
My god, I'm such an idiot. The solution is obvious :shock:

Code: Select all

@echo off

setlocal DisableDelayedExpansion

set $="This works^!" Even with a single caret^^, but how?

setlocal enableDelayedExpansion

Echo !$!

pause
exit
I am impressed. :D

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

Re: [solved] Hello world ! a special char

#7 Post by jeb » 02 Dec 2011 04:47

No, your solution produces :(
"This works^!" Even with a single caret^, but how?


I don't want the extra quotes nor the caret before the !.

My solution can echo text "as it" without any escaping :!:

Code: Select all

%MagicEcho% Ampersand & and pipe | works even in quotes " & | ! ^ "%MagicEnd%

produces
Ampersand & and pipe | works even in quotes " & | ! ^ "



Code: Select all

@echo off
cls
setlocal DisableDelayedExpansion
call :LoadMacros

setlocal EnableDelayedExpansion
%MagicEcho% This works! Even with a single caret^, but how? %MagicEnd%
%MagicEcho% Ampersand & and pipe | works even in quotes " & | ! ^ "%MagicEnd%
echo This fails! Even a single caret^ fails

echo(
setlocal DisableDelayedExpansion
%MagicEcho% This works! Even with a single caret^, and ampersand & and also in quotes "! &  ^" but how? %MagicEnd%


echo This works! Even a single caret^ fails
exit /b

:LoadMacros
set lf=^


set ^"MagicEnd=^%lf%%LF%)))"
set ^"\n=^^^%lf%%LF%^%lf%%LF%^^"
set MagicEcho=for /L %%n in (1 1 2) do @(@echo off%\n%
if %%n==2 (%\n%
<test.tmp (%\n%
      set /p line=%\n%
      set /p line=%\n%
   )%\n%
   echo(!line:~7,-1!%\n%
   endlocal%\n%
) ELSE (%\n%
> test.tmp (%\n%
    setlocal EnableDelayedExpansion%\n%
   prompt #%\n%
   @echo on%\n%
   for %%a in (1) do rem #
exit /b


Output wrote:This works! Even with a single caret^, but how?
Ampersand & and pipe | works even in quotes " & | ! ^ "
This fails Even a single caret fails

This works! Even with a single caret^, and ampersand & and also in quotes "! & ^" but how?
This works! Even a single caret fails


jeb

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: [solved] Hello world ! a special char

#8 Post by Ed Dyreen » 02 Dec 2011 05:28

'
So many tricks you are combining, I've got a headache from just looking at it.
I was doing some inferior experiments with the jeb append , in my code I have to escape the '( )' otherwise it fail :(

Code: Select all

%   % set ^"%$defines%=setLocal disableDelayedExpansion ^&for /l %%$ in ( 1, 1, 2 ) do if %%$ == 2 ( %$n1c%
%      % setLocal enableDelayedExpansion %$n1c%
%      % set "$p=^!$p:*(=^!" %$n1c%
%      % set "$?=^!$p:*)=^!" %$n1c%
%      % set "$p=^!$p^!###" %$n1c%
%      % !forQ_! ( "^!$?^!" ) do set "$p=^!$p:%%~?###=^!" %$n1c%
echo. %$n1c%
echo.$p=^^^!$p^^^!_ %$n1c%
%   % ) else set $p="

( %SetLocal_% ^( "thisFunctionWorks ^!" ^) ) &endlocal
   %SetLocal_%  ( "thisFunctionWorks ^!"  )   &endlocal
I will study this tomorrow, thanks jeb, it looks extremely interesting to play with :D See ya :mrgreen:

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

Re: [solved] Hello world ! a special char

#9 Post by jeb » 02 Dec 2011 05:48

Hi Ed,

your code can't use the full power of trick, you still need the carets before the exclamation marks.
And you use quotes for special characters.

The power of my trick is the power of REM.
It's the only command that can handle nearly all special characters without side effects.

I use the inner FOR-loop only to be able to redirect the output of the ECHO ON of the REM to an file.

hope it's obvious now :D
jeb

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: [solved] Hello world ! a special char

#10 Post by Ed Dyreen » 02 Dec 2011 20:07

'
I tried to eliminate this need, tried your code, but I am incapable eliminating the file dependency, and setting to a variable. :?
This obviously don't work:

Code: Select all

@echo off
cls
setlocal DisableDelayedExpansion
call :LoadMacros
call :Load_tooComplex

setlocal EnableDelayedExpansion

%MagicEcho% This works! Even with a single caret^, but how? %MagicEnd%
pause
exit /b


:Load_tooComplex
set ^"MagicEnd=`) do set "%%a" ^%lf%%LF%))"
set  MagicEcho=for /L %%n in (1 1 2) do @(@echo off%\n%
   if %%n==2 (%\n%
echo.a=%%a_%\n%
echo.var=!var!_%\n%
   ) ELSE (%\n%
      setlocal EnableDelayedExpansion%\n%
      prompt $%\n%
      @echo on%\n%
      for /f "usebackq eol=; delims=;" %%a in ( `rem var=
exit /b

Code: Select all

a=%a_
var=_
Druk op een toets om door te gaan. . .
:cry: I don't think it's possible to catch the output of a rem without needing a file redirect, I hope I prove to be wrong.
Ed Dyreen wrote:...echo ... in their own for in ( CMD ) clausule.
Wai-a-minute, I think I'm on to something .. :idea: ...

Code: Select all

@echo off
cls
setlocal DisableDelayedExpansion
call :LoadMacros
call :Load_tooComplex

setlocal EnableDelayedExpansion

%MagicEcho% This works! Even with a single caret^, but how?
@echo off
echo.
echo.!Magiclause! !MagicEcho! This works! Even with a single caret^, but how?
echo.
%Magiclause% %MagicEcho% This works! Even with a single caret^, but how? %Magicends%

pause
exit


:Load_tooComplex
set  ^"Magicends=^"^%lf%%LF%` ) do echo.1=%%1_"
set ^"Magiclause=for /f "usebackq tokens=*" %%1 in ( `cmd /V:on /q /c ^""
set   MagicEcho=setlocal EnableDelayedExpansion ^&prompt $ ^&@echo on ^&for %%a in (1) do rem #
exit /b

Code: Select all

rem # This works! Even with a single caret^, but how?

for /f "usebackq tokens=*" %1 in ( `cmd /V:on /q /c " setlocal EnableDelayedExpa
nsion &prompt $ &@echo on &for %a in (1) do rem # This works Even with a single
caret, but how? "

Druk op een toets om door te gaan. . .
Nope, I give up :x I can't prevent the magic end being eaten by rem, and the linefeed seems to break the for..

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Hello world ! a special char

#11 Post by Ed Dyreen » 04 Dec 2011 10:48

'
@Jeb, I believe you misinterpreted what I'm after, I don't just wan't to echo the input.
I want to catch it in a variable so I can operate on it. So my 4th post's solution still stands, and the initial escaping is required :?
Your solution works, but the aid of a file is not nice.

Feel free to prove me wrong, I've been trying that for a while ...

Post Reply