Reputation: 137
I want to find the index of 56 in "STS++5623+56+ 123 " . The code I have written gives me 6 (of 5623) but I need 11.
DEFINE var v-segment as longchar no-undo.
DEFINE VARIABLE v-element AS CHARACTER NO-UNDO.
ASSIGN v-segment = "STS++5623+56".
ASSIGN v-element = "56".
define variable v-index as integer no-undo.
v-index = index(v-segment , v-element , 1).
MESSAGE v-index
VIEW-AS ALERT-BOX INFO BUTTONS OK.
Upvotes: 0
Views: 2101
Reputation: 155
Sorry the previous answer wasn't what you needed. I decided to leave it up, because it is a nice solution to the problem as stated. But I'll try again. I made the check for delimiters a separate function so you can easily adapt it to your requirements. Adding multi-byte character capabilities should be straightforward.
DEFINE VARIABLE v-segment AS LONGCHAR NO-UNDO.
DEFINE VARIABLE v-element AS CHARACTER NO-UNDO.
DEFINE VARIABLE v-delims AS CHARACTER NO-UNDO.
DEFINE VARIABLE v-index AS INTEGER NO-UNDO.
DEFINE VARIABLE v-delimCount AS INTEGER NO-UNDO.
DEFINE VARIABLE v-segLength AS INTEGER NO-UNDO.
DEFINE VARIABLE v-eltLength AS INTEGER NO-UNDO.
DEFINE VARIABLE v-psn AS INTEGER NO-UNDO.
ASSIGN v-segment = "STS++5623+56"
v-element = "56"
v-delims = "+:"
/* For efficiency, don't calculate these inside your loop */
v-seglength = LENGTH( v-segment)
v-eltLength = LENGTH( v-element)
v-delimCount = LENGTH( v-delims).
/*
** isDelin()
** Is character at specified positiion one of the delimiters?
**
** Params:
** CHARACTER p-str - string to search
** INTEGER p-psn - position to check
** CHARACTER p-delims - list of delimiters to check for
**
** Returns TRUE if character at specified position is a delimiter
** Otherwise, returns FALSE
*/
FUNCTION isDelim RETURNS LOGICAL (
INPUT p-str AS LONGCHAR,
INPUT p-psn AS INTEGER,
INPUT p-delims AS CHARACTER
):
/* You might want parameter checking here.... */
RETURN INDEX( p-delims, SUBSTRING( p-str, p-psn, 1)) > 0.
END FUNCTION. /* isDelim */
/*
** You might want special case handling here:
** if v-eltLength = 0 then v-index = 1. return.
** IF v-element = ? or v-segment = ? then v-index = 0. return.
*/
/* Look for v-element, then see if it is surrounded by delimiters */
v-index = 0.
DO WHILE TRUE:
v-index = INDEX( v-segment, v-element, v-index + 1).
If v-index = 0 THEN LEAVE. /* No more matches */
/*
** Found a match. Is it preceded by a delimiter?
** (Don't check if match is at beginning of string.)
*/
v-psn = v-index - 1.
IF v-psn > 0 AND NOT isDelim( v-segment, v-psn, v-delims) THEN NEXT.
/*
** Is match followed by a delimiter?
** (Don't check if match is at end of string.)
*/
v-psn = v-index + v-eltLength.
IF v-psn > v-seglength THEN LEAVE.
IF NOT isDelim(v-segment, v-psn, v-delims) THEN NEXT.
/* Success! */
LEAVE.
END.
MESSAGE v-index VIEW-AS ALERT-BOX INFO BUTTONS OK.
Upvotes: 1
Reputation: 131
DEFINE var v-segment as longchar no-undo.
DEFINE VARIABLE v-element AS CHARACTER NO-UNDO.
def var v-i as int no-undo.
def var v-data as char no-undo.
ASSIGN v-segment = "STS++5623+56+123".
ASSIGN v-element = "56".
define variable v-index as integer no-undo.
do v-i = 1 to num-entries(v-segment,"+"):
if entry(v-i,v-segment,"+") = v-element then
do:
v-data = entry(v-i,v-segment,"+").
MESSAGE v-data VIEW-AS ALERT-BOX INFO BUTTONS OK.
end.
end.
Upvotes: 0
Reputation: 155
There are several ways to approach this. Which is smartest depends upon the data. I can think of two that do not involve loops, which may be what you are looking for. I haven't done any benchmarking, but I think the code below would is the most efficient algorithm. At most it involves three string searches -- one entry()
, one num-entries()
, and one index()
. If this doesn't meet your needs, I can suggest alternatives.
DEFINE VARIABLE v-segment AS LONGCHAR NO-UNDO.
DEFINE VARIABLE v-element AS CHARACTER NO-UNDO.
DEFINE VARIABLE v-index AS INTEGER NO-UNDO.
DEFINE VARIABLE v-entry AS INTEGER NO-UNDO.
DEFINE VARIABLE v-delim AS CHARACTER NO-UNDO.
ASSIGN v-segment = "STS++5623+56"
v-element = "56"
v-delim = "+".
/* Does the segment contain the exact entry? */
v-entry = LOOKUP(v-element, v-segment, v-delim).
/*
** If entry number = 0, then element is not found
** If entry number = 1, then element is at beginning of segment.
** If entry number = num-entries(), then element is at end of segment
** Otherwise, element is in the middle; just search for it surrounded
** by delimters.
*/
IF v-entry = 0 THEN
v-index = 0.
ELSE IF v-entry = 1 THEN
v-index = 1.
ELSE IF v-entry = NUM-ENTRIES( v-segment, v-delim) THEN
v-index = R-INDEX( v-segment, v-delim) + 1.
else
v-index = INDEX( v-segment, v-delim + v-element + v-delim) + 1.
MESSAGE v-index VIEW-AS ALERT-BOX INFO BUTTONS OK.
Upvotes: 0