request feature OPTION STARTPOINT 2
Dec 18, 2020 20:43:07 GMT 1
Post by rikky on Dec 18, 2020 20:43:07 GMT 1
so we have INSTRREV that searches for something backwards.
According to the documentation:
Returns the position where needle$ begins in haystack$, but start searching from the end of haystack$, optionally at position z also counting from the end. The result is counted from the beginning of haystack$. If not found then this function returns the value '0'.
See also OPTION STARTPOINT to return the result counted from the end of haystack$.
See also OPTION STARTPOINT to return the result counted from the end of haystack$.
That's nice and even very logical.
Until you start to examine JSON strings.
For then you are no longer searching for a needle in a haystack, but for a needle in a whole bunch of haystacks stashed upon each other.
You first have to INSTR to whatever you know already.
Then INSTR '}' for the end if the group.
Then INSTREV to the beginning of the group.
And this group might be part of a bigger group, which is part of an even bigger group, and all these groups might contain subgroups.
So you are going forward, backward, forward, backward, backward, forward, forward and backward again.
And every time you change direction, you have to recalculate the STARTPOINT, for OPTION STARTPOINT does not change the direction of the startpoint [,z] in INSTRREV(haystack$, needle$ [,z])
To clearify a few INSTRREV examples in BaCon4Bash format:
echo 123456789012345678901234567890 | INSTRREV 567
25
echo 123456789012345678901234567890 | INSTRREV 567 7
15
echo 123456789012345678901234567890 | INSTRREV 567 17
5
export STARTPOINT=TRUE
echo 123456789012345678901234567890 | INSTRREV 567
6
echo 123456789012345678901234567890 | INSTRREV 567 7
16
echo 123456789012345678901234567890 | INSTRREV 567 17
26
Horrible, if the string becomes complex, and you need the result for the next INSTR, and the result from that INSTR back for your next INSTRREV.
Now a few examples from the BaCon4Bash script INSTREV, attached below:
echo 123456789012345678901234567890 | INSTREV 567
25
echo 123456789012345678901234567890 | INSTREV 567 24
15
echo 123456789012345678901234567890 | INSTREV 567 14
5
Much easier, I think.
The next script is INSTREV.bac without the double 'R' that I wanted to publish in BaCon4Bash, but the
Code Projects chapter is currently occupied, so I do this here:
This thing is doing just what I want.
Never mind the whole bunch of functions and subs that are not used.
It's just the ever evolving template for BaCon4Bash.
So if you're interested, I suggest you start reading from the bottum up, and skip the sh*t.
Rik
OPTION EXPLICIT TRUE
GLOBAL version$
version$ = "0.14"
SUB HELP
PRINT
PRINT basename$ & " [option] " & Q$ & "haystack$" & Q$ & " " & Q$ & "needle$" & Q$ & " [<startpos>]"
PRINT
PRINT "haystack$ can also be piped into this command."
PRINT
PRINT "alternative for INSTRREV."
PRINT "INSTRREV needs a [startpos] counted from the end."
PRINT
PRINT "startpos is counted from the BEGINNING of the string."
PRINT "the returned result is also counted from the BEGINNING of the string."
PRINT
PRINT "options :"
PRINT " -v --version print version."
PRINT " -h --help print help."
PRINT
PRINT "example:"
PRINT "echo 123456789012345678901234567890 | INSTREV 567 20"
PRINT
END SUB
OPTION UTF8 TRUE
OPTION ERROR FALSE
OPTION COLLAPSE TRUE
OPTION BASE 1
DECLARE argument$ ASSOC STRING
GLOBAL basename$ = BASENAME$(TOKEN$(ARGUMENT$,1))
GLOBAL verbose = 0
GLOBAL dryrun = 0
GLOBAL retval = 0
GLOBAL input$
GLOBAL var
GLOBAL Q$ = CHR$(34) : ' quote
GLOBAL BS$ = CHR$(92) : ' backslash
CATCH ERROR help
SUB help(function_name$, filename$, lineno)
EPRINT ERR$(ERROR), " in function ", function_name$, " in file '", filename$, "' at line ", lineno
END 123
END SUB
FUNCTION GET_STDIN$()
LOCAL string$ TYPE STRING
LOCAL stndin
WHILE TRUE
stndin = WAIT(STDIN_FILENO, 50)
IF stndin = 0 THEN BREAK
string$ = string$ & CHR$(stndin)
WEND
IF string$ <> "" THEN string$ = RIP$(string$,-1)
RETURN string$
END FUNCTION
SUB THE_COMPUTER_SAYS_NO(lineno)
EPRINT basename$ & ": The computer says no, in line " & STR$(lineno)
IF retval THEN END retval
END 1
END SUB
FUNCTION CHAR$(string$,number)
RETURN MID$(string$,number,1)
END FUNCTION
FUNCTION LASTCHAR$(string$)
RETURN RIGHT$(string$,1)
END FUNCTION
SUB SELECT_ARGUMENT
LOCAL i
LOCAL option$
LOCAL counter = 0
FOR i = 2 TO AMOUNT(ARGUMENT$)
option$ = FLATTEN$(TOKEN$(ARGUMENT$,i))
SELECT option$
CASE "-v";
CASE "--version"
PRINT basename$ & " version : " & version$
END 0
CASE "--help";
CASE "-h"
HELP
END 0
CASE "--verbose"
INCR verbose
CASE "--dryrun"
dryrun = 1
DEFAULT
IF LEFT$(option$,1) = "-" THEN
EPRINT "wrong option"
THE_COMPUTER_SAYS_NO(LINENO)
END IF
INCR counter
argument$(STR$(counter)) = option$
END SELECT
NEXT i
END SUB
FUNCTION ISNUMBER(string$)
'This function returns TRUE if the string$ has a numeric value.
LOCAL char$
LOCAL i
string$ = CHOP$(string$)
IF LEFT$(string$,1) = "+" OR LEFT$(string$,1) = "-" THEN
string$ = RIP$(string$,1,1)
END IF
'we might have one point in it.
IF INSTR(string$,".") THEN
string$ = RIP$(string$,INSTR(string$,"."),1)
ENDIF
IF INSTR(string$,".") THEN RETURN 0
IF LEN(string$) = 0 THEN RETURN 0
FOR i = 1 TO LEN(string$)
char$ = MID$(string$,i,1)
IF VAL(char$) = 0 THEN
IF char$ <> "0" THEN
RETURN 0
END IF
END IF
NEXT i
RETURN 1 : 'VAL(string$) gives wrong value for zero.
END FUNCTION
FUNCTION ISHEX(string$)
' The value for x$ can lie between 0 and 0x10FFFF. (who cares, it's not this function's job.)
' 0x means hexadecimal
' returns 1 if TRUE
LOCAL i
LOCAL char$
IF LEFT$(string$,2) <> "0x" THEN RETURN 0
IF LEN(string$) = 2 THEN RETURN 0
FOR i = 3 TO LEN(string$)
char$ = CHAR$(string$,i)
IF NOT(ISTOKEN("0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f",char$)) THEN RETURN 0
NEXT i
RETURN 1
END FUNCTION
SUB SHUFF_DOWN
'shifts the argument array one down
'argument$("1") now becomes empty
LOCAL i
FOR i = NRKEYS(argument$) TO 1 STEP -1
argument$(STR$(i+1)) = argument$(STR$(i))
NEXT i
argument$("1") = ""
END SUB
SUB UNJSON$(string$)
LOCAL counter
LOCAL result$
LOCAL i
LOCAL char$
FOR i = 1 TO LEN(string$)
char$ = CHAR$(string$,i)
IF counter < 0 THEN counter = 0
IF char$ = "[" OR char$ = "{" THEN
counter = counter+3
PRINT NL$ & SPC$(counter);
CONTINUE
END IF
IF char$ = "]" OR char$ = "}" THEN
counter = counter-3
PRINT NL$ & SPC$(counter);
CONTINUE
END IF
IF char$ = "," THEN
PRINT NL$ & SPC$(counter);
CONTINUE
END IF
PRINT char$;
NEXT i
END SUB
FUNCTION PRINT_FORMAT$(digits)
'GLOBAL zero_digits$ = "%.0f"
'GLOBAL one_digit$ = "%.1f"
'GLOBAL two_digits$ = "%.2f"
LOCAL return$ = "%." & STR$(digits) & "f"
RETURN return$
'PRINT VAL("123") / VAL("8") FORMAT PRINT_FORMAT$(3)
END FUNCTION
FUNCTION INSTREV(VAR bla$ SIZE size)
'alternative for INSTRREV.
'INSTRREV needs a [startpos] counted from the end: BAH.
'note: all arguments must be strings.
'format: INSTREV(haystack$,needle$,[startpos])
'startpos is counted from the BEGINNING of the string.
'the returned result is also counted from the BEGINNING of the string.
'OPTION BASE 1 is presumed.
LOCAL startpos = 0
LOCAL pos
LOCAL haystack$
LOCAL needle$
LOCAL char$
IF size < 2 THEN
EPRINT "Wrong format for function INSTREV"
THE_COMPUTER_SAYS_NO(LINENO)
END IF
IF size > 3 THEN
EPRINT "Wrong format for function INSTREV"
THE_COMPUTER_SAYS_NO(LINENO)
END IF
IF size = 3 THEN
IF bla$[3] = "" THEN bla$[3] = STR$(LEN(bla$[1]))
IF NOT(ISNUMBER(bla$[3])) THEN
EPRINT "startpos is NOT a number in function INSTREV"
THE_COMPUTER_SAYS_NO(LINENO)
END IF
IF INSTR(bla$[3],"+") OR INSTR(bla$[3],"-") OR INSTR(bla$[3],".") THEN
EPRINT "startpos is NOT a number in function INSTREV"
THE_COMPUTER_SAYS_NO(LINENO)
END IF
END IF
haystack$ = bla$[1]
needle$ = bla$[2]
startpos = VAL(bla$[3])
pos = LEN(haystack$)
IF startpos < pos THEN pos = startpos
IF haystack$ = "" OR needle$ = "" THEN
'yes, this is possible.
'INSTREV("","")
RETURN 0
END IF
char$ = CHAR$(needle$,1)
WHILE TRUE
IF CHAR$(haystack$,pos) = char$ THEN
IF MID$(haystack$,pos,LEN(needle$)) = needle$ THEN BREAK
END IF
IF pos = 0 THEN BREAK
DECR pos
WEND
RETURN pos
END FUNCTION
SELECT_ARGUMENT
'this one AFTER figuring out the ARGUMENT$
'OPTION QUOTED FALSE
input$ = GET_STDIN$()
IF LEN(input$) != 0 THEN
SHUFF_DOWN
argument$("1") = RIP$(input$,-1)
END IF
PRINT INSTREV(argument$("1"),argument$("2"),argument$("3"))