Jump to content











Photo
- - - - -

[Release] str_repl.g4b i.e. script for string replacement


  • Please log in to reply
8 replies to this topic

#1 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 10 August 2021 - 04:13 PM

This is something that is missing in grub4dos batch but that exists in NT batch:

%string:find=replace%

this script attempts to allow something similar, though not exactly the same, I am not fully convinced of its "universal" usefulness, as there are a couple issues that I seem not to be able to workaround, namely there is too much risk of an endless loop, hence a default of 1 pass, equating to "find a replace first occurence only"  is implemented, that can be manually overridden with a parameter and it is not possible to use a <find> that is a subset of <replace>.

 

Anyway, having it sitting in my hard disk is of no use and maybe can be useful to someone (within its limits) or can be of inspiration for something better.

!BAT
#str_repl function to replace string in string
#analogous to (but different from) the NT batch use of %string:x=y%
#parameters <string> <find> <replace> [<num of occurrencies, default 1>]
#use double quotes around any of <string>, <find>, <replace> if they contain space(s)
#use double quoted empty string for replace to delete <find>
setlocal
set str=%~1
set fnd=%~2
set /a length=%@retval%+1 > nul
if %4.==. set /a cnt=1 > nul || set /a cnt=%4 > nul
call Fn.11 "%str%" "%str:~0,1%"
set /a base=%@retval%  > nul
:loop
call Fn.11 "%~3" "%~2"
if not %@retval%==0 set str && goto :eof
call Fn.11 "%str%" "%~2"
set /a left=%@retval% > nul
if %left%==0  set str && goto :eof
set /a left=%left%-%base% > nul
call set before=%str^:~0,%left%%%
set /a off=%left%+%length%-1 > nul
call set after=%str^:~%off%%%
set str=%before%%%~3%%after%
set /a cnt=%cnt%-1 > nul
if not %cnt%==0 goto :loop
:output
set str

goto :eof

Needs to be tested and refined (and optionally transformed into an actually useful callable function).

 

:duff:

Wonko

Attached Files



#2 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 11 August 2021 - 08:29 PM

(.....) there are a couple issues that I seem not to be able to workaround, namely there is too much risk of an endless loop, hence a default of 1 pass, equating to "find a replace first occurence only"  is implemented, that can be manually overridden with a parameter and it is not possible to use a <find> that is a subset of <replace>.

Really a very, very nice script!

 

I have learned a lot about Fn.11-specific *things*, while fixing these two issues mentioned.



#3 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 12 August 2021 - 08:41 AM

I have now a (really, and I mean really) ugly workaround for the  <find> that is a subset of <replace>.

 

If we (temporarily) substitute a "surely" non-existing string , as an example "§§§§§§§§", to <replace> the issue is solved.

 

This approach can be used in two different ways:
1) assume that "§§§§§§§§" will never exist in <string> and always do two passes
2) assume (almost) nothing, and only use "§§§§§§§§" only when the <find> is actually a subset of <replace>

 

#1 will be slower (if speed is of concern)

#2 will make the code bigger, and there will always be the extremely rare case of "§§§§§§§§" actually existing.

 

A rough attempt to #2 follows



!BAT
#str_repl function to replace string in string
#analogous to (but different from) the NT batcH use of %string:x=y%
#parameters <string> <find> <replace> [<num of occurrencies default 1]
#use double quotes around any of <string>, <find>, <replace> if they contain space(s)
#use double quoted empty string for replace to delete <find>
setlocal
set str=%~1
set fnd=%~2
set /a length=%@retval%+1 > nul
set repl=%~3
if %4.==. set /a cnt=1 > nul || set /a cnt=%4 > nul
set fixcnt=%cnt% 

call Fn.11 "%str%" "%str:~0,1%"
set /a base=%@retval%  > nul

:loop
#let's check that find is NOT a subset of repl
call Fn.11 "%~3" "%~2"
#if not %@retval%==0 set str && goto :eof
if not %@retval%==0 call :ch_repl

#let's find the offset to the string to be replaced (if any)
call Fn.11 "%str%" "%~2"
set /a left=%@retval% > nul
if %left%==0  set str && goto :eof
set /a left=%left%-%base% > nul

#let's find whatever is on left side of the string to be replaced
call set before=%str^:~0,%left%%%

#let's find whatever is on right side of the string to be replaced
set /a off=%left%+%length%-1 > nul
call set after=%str^:~%off%%%
set str=%before%%%repl%%%after%
set /a cnt=%cnt%-1 > nul
if not %cnt%==0 goto :loop
if %chrepl%.==1. goto :re_run

:output
set str

goto :eof

:ch_repl
#let's check that chars §§§§§§§§ are not a subset of string (they won't likely be)
call Fn.11 "%string%" "§§§§§§§§"
if not %@retval%==0 goto :eof
#let's check that chars §§§§§§§§ are also not a subset of replace (they won't likely be)
call Fn.11 "%repl%" "§§§§§§§§"
#but if they are no substitution will take place
if not %@retval%==0 goto :eof
set oldrepl=%repl%
set repl=§§§§§§§§
set ch_repl=1
goto :eof

:re_run
set cnt=%fixcnt%
set fnd=§§§§§§§§
set repl=%oldrepl%
set ch_repl=0
goto :loop
goto :eof

:duff:

Wonko



#4 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 12 August 2021 - 12:44 PM

:) It's not working. Not only because of using %string% once instead of %str%. But can be fixed:

!BAT
#str_repl.G4B, v0.2 by Wonko the Sane, fixes by deomsh
#str_repl function to replace string in string
#analogous to (but different from) the NT batcH use of %string:x=y%
#parameters <string> <find> <replace> [<num of occurrencies default 1]
#use double quotes around any of <string>, <find>, <replace> if they contain space(s)
#use double quoted empty string for replace to delete <find>
setlocal
set "str=%~1"
set "fnd=%~2"
set /a length=%@retval% > nul
set "repl=%~3"
if %4.==. set /a cnt=1 > nul || set /a cnt=%4 > nul
set /a fixcnt=%cnt% > nul 

call Fn.11 "%str%" "%str:~0,1%"
set /a base=%@retval%  > nul

:loop
#let's check that find is NOT a subset of repl
call Fn.11 "%~3" "%~2"
#if not %@retval%==0 set str && goto :eof
if not %@retval%==0 call :ch_repl

#let's find the offset to the string to be replaced (if any)
call Fn.11 "%str%" "%fnd%"
set /a left=%@retval% > nul
if %left%==0  set str && goto :eof
set /a left=%left%-%base% > nul

#let's find whatever is on left side of the string to be replaced
call set "before=%str^:~0,%left%%%"

#let's find whatever is on right side of the string to be replaced
set /a off=%left%+%length% > nul
if %fnd%==§§§§§§§§ set /a off=%off%+7 > nul
call set "after=%str^:~%off%%%"
set "str=%before%%%repl%%%after%"
set /a cnt=%cnt%-1 > nul
#set && pause
if not %cnt%==0 goto :loop
if %chrepl%.==1. goto :re_run

:output
set str

goto :eof

:ch_repl
#let's check that chars §§§§§§§§ are not a subset of string (they won't likely be)
call Fn.11 "%str%" "§§§§§§§§"
if not %@retval%==0 goto :eof
#let's check that chars §§§§§§§§ are also not a subset of replace (they won't likely be)
call Fn.11 "%repl%" "§§§§§§§§"
#but if they are no substitution will take place
if not %@retval%==0 goto :eof
set "oldr

BTW First I tried +8 in my addition if %fnd%==§§§§§§§§ set /a off=%off%+7 > nul but +8 didn't work?  :unsure:

 

BTW2 There are also issues with spaces, so that's why I added double qoutes, maybe too much.  :ph34r:

 

BTW3 Loop's seems to be fixed in your  second version of str_repl.g4b  :)

 

BTW3 The extra loops are indeed slower, at least in Limbo x86 on my smartphone, can't test on real hardware now (holiday, no PC available).

 

All in all I prefer my own fixes (I can show them if you like).



#5 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 12 August 2021 - 01:28 PM

Sure, the idea is to show them, then we can choose what works best/is cleaner.

 

BTW, about this:

http://reboot.pro/in...=22539&p=218998

it is possible (if you run the grub4dos in Virtualbox) to connect the (virtual) serial of virtualbox to a named pipe, then connect Putty to the pipe).

In grub4dos (inside the Virtualbox) you issue:

serial ( or serial --unit=0)

terminal serial

and then you can use Putty as the grub4dos console (and copy the output to text).

There are caveats, however:

1) backspace doesn't work (but moving left with right arrow and then use delete works)
2) I have found no way to restore the terminal to console :dubbio:[1]

 

The general idea (and needed details for the settings in virtualbox and Putty) comes from here:

https://www.haiku-os...dows-debugging/

 

 

:duff:

Wonko

 

[1] except one (ugly)  that is issuing in the Putty terminal:

chainloader /grldr

boot

(which of course means to reset the grub4dos instance in Virtualbox)

 

Forget the above, it works, it only seems that it doesn't.

A good idea would to issue on the Putty:

terminal console && echo Back to normality 

BUT it seems like working sometimes and sometimes not :unsure:

terminal console &; clear

seems to work more reliably



#6 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 12 August 2021 - 11:04 PM

Thanks a lot for the Putty info. I will test when I'm home again.

 

About my fixes of your script: I choose to split the string in a part 'strleft' and a part 'done' ('strleft' became var 'stl', with different length of var-names Fn.11-output was not compatible with base - I had to learn the hard way).

Only of importance after the first pass. Also 'base' must be set in the loop with my fix.

 

This is the function STRREPL.LLL I made, some gadgets included:

!BAT
#STRREPL.LLL v0.1 (20210811), by deomsh. Based on script str_repl.g4b by Wonko the Sane
#Function: Searches string in string and replace, result is string after replacement(s)
#Use: StrReplace string find replace [N|all]
#Mandatory Arguments: string find replace, all strings, if containing spaces: between double quotes!
#Optional Arguments: N|all, max number of searchings & replacements (default is 1)
#Remarks: Max (output) length max 511 chars in a string.
#debug 0
#echo %*
call :%~1 %*
echo Function: %~1 $[0x07]result=%result%
goto :eof

:StrReplace
setlocal && set *
set "str=%~2"
set /a strlen=%@retval% > nul
set "strorg=%str%"
set "fnd=%~3"
set /a fndlen=%@retval% > nul
set "repl=%~4"
set /a repllen=%@retval% > nul
set /a calclen=%strlen% / %fndlen% * %repllen% > nul
if not %calclen%<=511 && echo Length of output: %calclen% greater then 511 chars && endlocal && goto :eof
set /a cntmax=%strlen% / %fndlen% > nul
if not "%~5"=="" && if not /i "%~5"=="all" &; set /a cnt=%~5 > nul ! if not /i "%~5"=="all" && set /a cnt=1 > nul
if /i "%~5"=="all" && set /a cnt=%cntmax% > nul
set "stl=%str%"
set /a found=0 > nul
:LoopStrReplace
#echo $[0x07]stl=%stl% cnt=%cnt%
if not exist stl && endlocal && set "result=%str%" && goto :eof
call Fn.11 "%stl%" "%stl:~0,1%"
set /a base=%@retval% > nul
call Fn.11 "%stl%" "%fnd%"
set /a left=%@retval% > nul
#echo $[0x07]stl=%stl% strlen=%strlen% fndlen=%fndlen% left=%left% base=%base% cnt=%cnt%
if %left%==0 && if %found%==0 && echo $[0x07]%fnd% not found in %str% && endlocal && set result= && goto :eof
if %left%==0 && if %found%>=1 && endlocal && set "result=%str%" && goto :eof
set /a found=%found% + 1 > nul
set /a left=%left% - %base% > nul
call set "before=%^stl:~0,%left%%%"
#echo $[0x07]before=%before% left=%left% cnt=%cnt%
set /a off=%left%+%fndlen% > nul
call set "after=%stl^:~%off%%%"
#echo $[0x07]after=%after% off=%off% cnt=%cnt%
set "str=%done%%%before%%%repl%%%after%"
set "done=%done%%%before%%%repl%"
set /a donelen=%@retval% > nul
#echo $[0x07]done=%done% donelen=%donelen% cnt=%cnt%
set /a cnt=%cnt% - 1 > nul
if not %cnt%==0 && set /a strlen=%strlen% - %fndlen% > nul && call set "stl=%^str:~%donelen%%%" > nul && goto :LoopStrReplace
:output
#echo $[0x07]%str%
endlocal && set "result=%str%"
goto :eof

BTW I tested various combinations, I found no problems anymore. Can be still there... :ph34r:

 

This is the output, converted with https://image2text.site/ (not too bad for standard text, only a few glitches):

Limbo x86 PC Emulator
grub> strrepl.lll StrReplace "W W W..." W Wonko all
stl=W W W... cnt=8
stl=W W W... strlen=8 fndlen=1 left=3838252 base=3838252 cnt=8
before= left=0 cnt=8
after= W W... off=1 cnt=8
done=Wonko donelen=5 cnt=8
stl= W W... cnt=7
stl= W W...
strlen=7 fmdlen=1 left=3838253 base=3838252 cnt=7
before=
left=1 cnt=7
after= W... off=2 cnt=7
done=Wonko Wonko donelen=11 cnt=7
stl= W... cnt=6
stl= W... strlen=6 fndlen=1 left=3838253 base=3838252 cnt=6
before=
left=1 cnt=6
after=... off=2 cnt=6
done=Wonko Wonko Wonko donelen=17 cnt=6
stl=... cnt=5
stl=... strlen=5 fndlen=1 left=0 base=3838252 cnt=5
Function: StrReplace result=Wonko Wonko Wonko...
grub>

BTW My debug-echos included.



#7 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 13 August 2021 - 08:25 AM

Very, very nice. :)

 

If I may, a few bytes can be saved by replacing:

 

if not exist stl && endlocal && set "result=%str%" && goto :eof

with:

if not exist stl && goto :output

 

and:

 

 

if %left%==0 && if %found%>=1 && endlocal && set "result=%str%" && goto :eof

with

if %left%==0 && if %found%>=1 && goto :output

 

and possibly :unsure: a couple more of these can be simplified moving the 

if %found%==0 &&

and

if %found%==1 &&

 

to :output

 

:duff:

Wonko



#8 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 13 August 2021 - 06:05 PM

Very, very nice. :)

Almost all credits should go to you. I fixed only a bit (my gadgets are another story). For me it is a good exercise to make changes to an existing script, gives 'deeper' understanding.

If I may, a few bytes can be saved by replacing: with: if not exist stl && goto :output and: with if %left%==0 && if %found%>=1 && goto :output

Can be done. Good idea in case of saving bytes. But is it faster, jumping to an extra label? (Can't test for now - Limbo x86 is far to slow for any meaningfull looptest).

and possibly :unsure: a couple more of these can be simplified moving the if %found%==0 && and if %found%==1 && to :output

I don't understand, these lines are intended to get out the loop (together with 'if not exist stl'. Can you explain?

to :output

Oeps, should be ':OutputStrReplace' - I didn't take notice of this label, because it wasn't used. I try to give generic labels like ':loop' specific names in .lll-functions. Just in case they are collected in one file (if ever...). :wacko:

#9 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 13 August 2021 - 06:50 PM

Right now what determines the "exit" is the if %left%==0 (unless %found% is expected to be negative):

 

if %left%==0 && if %found%==0 && echo $[0x07]%fnd% not found in %str% && endlocal && set result= && goto :eof
if %left%==0 && if %found%>=1 && endlocal && set "result=%str%" && goto :eof

 

then different behaviour depends on the value of %found% 

 

so it could be something *like*::

 

...

if %left%==0 goto :OutputStrReplace

 

 

:OutputStrReplace

endlocal && set "result=%str%"
if %found%=0 echo $[0x07]%fnd% not found in %result% && set "result="

goto :eof

 

:unsure:

 

the goto :eof should take the same time as the goto :OutputStrReplace, there is not any extra goto :dubbio:

 

:duff:

Wonko






1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users