|
<< Click to Display Table of Contents >> Navigation: 3. Script Language > String commands > !STR.- String Command > Instring - Find Commands > String Operations |
MiniRobotLanguage (MRL)
STR.XInstr
Case-Sensitive Nth String Search
Intention
This command searches for the nth occurrence of a specified string (P2) within a source string (P1), starting from an optional position (P4). The occurrence number is specified by P3 (positive for left-to-right counting, negative for right-to-left counting). An optional overlap flag (P5) allows overlapping matches (default FALSE).
The search is case-sensitive (e.g., "Hello" does not match "hello"). The result is the 1-based position of the nth match (or 0 if not found), placed on the Top of Stack (TOS) or in an optional variable (P6).
If P4 is positive (or 0, defaults to 1), it searches left-to-right from that position. If negative (e.g., -1), it searches right-to-left from the end (or |P4| bytes from end). The result is always a 1-based position from the start of the string.
Overlap (P5=1) allows counting overlapping occurrences (e.g., "aa" in "aaa" counts 2 with overlap, 1 without). This command is useful for finding specific instances of a substring in text processing tasks, such as parsing logs or structured data, without modifying the source string.
Schematic (Forward and Reverse Nth Search with Overlap)
Source: aaa
Search: aa, N=2, Start=1, Overlap=1 (LTR) --> Pos=2
Search --> |a|a|a|
^ ^ (1st at 1, 2nd at 2 with overlap)
Search: aa, N=2, Start=-1, Overlap=1 (RTL) --> Pos=1
Search <-- |a|a|a|
^ ^ (2nd at 1 from end)
Without overlap (P5=0): Counts 1 (at 1 or 2, depending on direction).
Syntax
STR.XInstr|P1|P2|P3[|P4][|P5][|P6]
Parameter Explanation
•P1 - (Source String) The main string to search within. Variable or literal.
•P2 - (Search String) The string to search for. Variable or literal.
•P3 - (Occurrence Number) Numeric, nth occurrence (positive for left-to-right counting, negative for right-to-left counting).
•P4 - (Optional Start Position) Numeric, 1-based (default 1). If negative, searches right-to-left from end or |P4| bytes from end.
•P5 - (Optional Overlap Flag) Numeric, 1 to allow overlapping matches (default 0).
•P6 - (Optional Result Variable) Variable to store the result (position or 0).
Examples
' Forward search for 2nd occurrence to TOS
$$TXT=HelloWorldHello
$$SEA=Hello
STR.XInstr|$$TXT|$$SEA|2|1
POP.$$RES
' $$RES = 11 (2nd "Hello")
' Reverse search for 2nd occurrence to variable
$$TXT=HelloWorldHello
$$SEA=Hello
STR.XInstr|$$TXT|$$SEA|-2|-1|0|$$POS
' $$POS = 1 (2nd "Hello" from end)
' Forward search with overlap for 2nd aa in aaa (overlap=1, pos=1)
$$TXT=aaa
$$SEA=aa
STR.XInstr|$$TXT|$$SEA|2|1|1
POP.$$RES
' $$RES = 2 (2nd "aa" with overlap)
' =================================================================
' SELF-VALIDATING TEST SCRIPT for STR.XInstr (Unified Nth String Search)
' Purpose: Verify forward/reverse search using P3 sign, P4 dual meaning,
' overlap, and edge cases. Case-sensitive only.
' Stack: Pushes 1 item: TOS = position (1-based from start, 0 if not found).
' =================================================================
' --- Initialize Pass/Fail counters ---
$$PAS=0
$$FAI=0
STS.CLEAR
PRT. ===================================================
PRT. 1. FORWARD SEARCH TESTS (P3 > 0)
PRT. ===================================================
$$SRC=HelloWorldHello
PRT. Test 1.1: Forward 1st "Hello" (P3=1)...
STR.XInstr|$$SRC|Hello|1|1
POP.$$POS
$$EXP=1
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 1.2: Forward 2nd "Hello" (P3=2)...
STR.XInstr|$$SRC|Hello|2|1
POP.$$POS
$$EXP=11
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 1.3: Forward with start position (P4=6)...
STR.XInstr|$$SRC|Hello|1|6
POP.$$POS
$$EXP=11
IVV.$$POS=$$EXP
PRT. -> PASS (skips first "Hello")
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. ===================================================
PRT. 2. REVERSE SEARCH TESTS (P3 < 0)
PRT. ===================================================
PRT. Test 2.1: Reverse 1st "Hello" (P3=-1)...
STR.XInstr|$$SRC|Hello|-1|-1
POP.$$POS
$$EXP=11
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 2.2: Reverse 2nd "Hello" (P3=-2)...
STR.XInstr|$$SRC|Hello|-2|-1
POP.$$POS
$$EXP=1
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 2.3: Reverse with start from end (P4=-5)...
' Start 5 chars from end in "HelloWorldHello" (len=15) ? pos=11
' Should find "Hello" at 11
STR.XInstr|$$SRC|Hello|-1|-5
POP.$$POS
$$EXP=1
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. ===================================================
PRT. 3. OVERLAP TESTS
PRT. ===================================================
$$SRC=aaa
PRT. Test 3.1: Forward overlap (P5=1) — 2nd "aa" in "aaa"...
STR.XInstr|$$SRC|aa|2|1|1
POP.$$POS
$$EXP=2
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 3.2: Forward no overlap (P5=0) — 2nd "aa" not found...
STR.XInstr|$$SRC|aa|2|1|0
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 3.3: Reverse overlap — 2nd "aa" from end...
STR.XInstr|$$SRC|aa|-2|-1|1
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. ===================================================
PRT. 4. EDGE CASE TESTS
PRT. ===================================================
PRT. Test 4.1: No match (forward)...
$$SRC=Hello
STR.XInstr|$$SRC|xyz|1|1
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 4.2: No match (reverse)...
STR.XInstr|$$SRC|xyz|-1|-1
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 4.3: Empty source...
$$SRC=
STR.XInstr|$$SRC|test|1|1
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 4.4: Empty search string...
STR.XInstr|Hello||1|1
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 4.5: Pattern longer than source...
STR.XInstr|Hi|Hello|1|1
POP.$$POS
$$EXP=0
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. ===================================================
PRT. 5. BOUNDARY & SPECIAL CASES
PRT. ===================================================
PRT. Test 5.1: P4=0 defaults to 1 (forward)...
$$SRC=HelloWorld
STR.XInstr|$$SRC|o|2|0
POP.$$POS
$$EXP=7
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 5.2: P4=0 defaults to end (reverse)...
STR.XInstr|$$SRC|o|-2|0
POP.$$POS
$$EXP=5
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 5.3: Match at very end (forward)...
$$SRC=EndsWithHello
STR.XInstr|$$SRC|Hello|1|1
POP.$$POS
$$EXP=9
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 5.4: Match at very start (reverse)...
STR.XInstr|$$SRC|Ends|-1|-1
POP.$$POS
$$EXP=1
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. Test 5.5: Negative P3 with positive P4 (should treat as reverse start)...
' P4=10 in reverse mode = start from 10th char from end
STR.XInstr|HelloWorldHello|Hello|-1|10
POP.$$POS
$$EXP=11
IVV.$$POS=$$EXP
PRT. -> PASS
VIC.$$PAS
ELS.
$$MSG= -> FAIL - Expected: $$EXP, Actual: $$POS
PRT.$$MSG
VIC.$$FAI
EIF.
STS.CLEAR
PRT. ===================================================
PRT. TEST SUMMARY
PRT. ===================================================
CAL.$$TOT=$$PAS+$$FAI
$$MSG=Total Tests: $$TOT
PRT.$$MSG
$$MSG=Passed: $$PAS
PRT.$$MSG
$$MSG=Failed: $$FAI
PRT.$$MSG
' --- Display final result message box ---
IVV.$$FAI=0
MBX.SUCCESS: All tests passed!|Test Result|64
ELS.
$$MSG=FAILURE: $$FAI of $$TOT tests failed.
MBX.$$MSG|Test Result|16
EIF.
ENR.
Remarks
-Case-sensitive search; "Hello" does not match "hello".
-P3 positive: counts left-to-right; negative: counts right-to-left.
-P4=0 defaults to 1 (LTR) or end (RTL based on P3 sign).
-P5=1 allows overlapping (e.g., "aa" in "aaa" finds 2); default 0 (non-overlapping).
-Result is always pushed to TOS, even if P6 is specified.
-If nth occurrence not found or search string longer than remaining source, returns 0.
-Binary-safe for P1 and P2; no special/system vars expanded.
-For case-insensitive search, use STR.CiInstr; for patterns, use STR.FindAny.
Limitations
-No wildcard or pattern support; use STR.FindAny for patterns.
-P3 must be non-zero; invalid values may cause undefined behavior.
-No reverse direction for positive P3; use negative P3/P4 for RTL counting.
See also: