Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

SUBSTR() from right? 8

Status
Not open for further replies.

Neil Toulouse

Programmer
Mar 18, 2002
882
GB
Before I embark on a rather complex function, is there an equivalent of SUBSTR() that works from the right, eg
Code:
SUBSTR('TOULOUSE', 4, 1)
to give 'O' instead of 'L'?

I don't need any workaround code examples if there isn't a native function, as I will do that myself. Just looking for a quick way!

TIA
Neil

I like work. It fascinates me. I can sit and look at it for hours...
 
Unfortunately not, as you can only do:

RIGHT( 'Toulouse', 4 ) (to give "OUSE")

and not:

RIGHT( 'Toulouse', 4, 1 )

I like work. It fascinates me. I can sit and look at it for hours...
 
Oh yes, sorry to raise your hopes. Be interested to see your solution.

Stewart
 
A quick UDF did the trick:

Code:
FUNCTION SubstrR()
	LPARAMETERS tcString, tnPos, tnLen
	LOCAL lcResult, lnFor, lcNewString

	lcNewString = ''

	FOR lnFor = LEN(ALLTRIM(tcString)) TO 1 STEP -1
		lcNewString = lcNewString + SUBSTR( ALLTRIM(tcString), lnFor, 1 )
	ENDFOR

	lcResult = SUBSTR( ALLTRIM(lcNewString), tnPos, tnLen )

	RETURN lcResult
ENDFUNC

I like work. It fascinates me. I can sit and look at it for hours...
 
I've added it as an FAQ if anyone finds it useful!

faq184-5934

Neil

I like work. It fascinates me. I can sit and look at it for hours...
 
I think there is an easier way
Code:
FUNCTION SubstrR(tcString, tnPos, tnLen)
    RETURN LEFT(RIGHT(tcString,tnPos),tnLen)
ENDFUNC

Borislav Borissov
 
Borislav,

That actually gives a different result from Neil's function when you set the 3rd para to 2 or more.

Stewart
 
If the string is very long you might not want to turn it completely before you retrieve your substr.
Code:
FUNCTION SubstrR()
    LPARAMETERS tcString, tnPos, tnLen

    LOCAL lnRef, lnFor, lcNewString, lcString

*   Wouldn't do that as you might sometimes want it to be unchanged...
    lcString = Alltrim( tcString )

	lnRef = Len( lcString ) - tnPos

    lcNewString = ''
	FOR lnFor = lnRef + 1 TO lnRef - tnLen + 2 STEP -1
        lcNewString = lcNewString + SUBSTR( ALLTRIM(lcString), lnFor, 1 )
    ENDFOR

    RETURN lcNewString
ENDFUNC

Volker/
 
It would be nice, if the sign of a parameter of Substr would state from which side or in which direction to count...

? substr("hello world",1,4)
=> "hell"

? substr("hello world",-3,-3)
=> "row"

Or the same with nStartpos counted from left (as usual):
? substr("hello world",9,-3)
=> "row"

I also see no better way to reverse a string as to rebuild it char by char...

Bye, Olaf.
 
Hi Olaf!

Liked your ideas so have incorporated them in the FAQ!

Neil

I like work. It fascinates me. I can sit and look at it for hours...
 
Star for FatSlug for the FAQ and Star to OlafDoschke for a really good idea on how to expand on this. I've gone through the code and fixed a logical error, streamlined it abit, allowed for the alltrim() to be optional with an additional parameter (sometimes spaces are intended and needed) and gave it a name more indicative of its present functionality... hope you don't mind. I really like the idea, it is even a candidate for a real extension for the SubStr() function in a future VFP as it is backward compatible with existing code. Though the VFP Team is working on Sedna, it still struck me as a very nice extension to an existing function.
Code:
*** Examples of Use
? SUBSTREX( 'TOULOUSE', 4, 1) && returns "L"
? SUBSTREX( 'TOULOUSE', 4, -2) && returns "LU"
? SUBSTREX( 'TOULOUSE', -4, 2) && returns "OU"
? SUBSTREX( 'TOULOUSE', -4, -2) && returns "OL"
? SUBSTREX( 'TOULOUSE', 2) && returns "OULOUSE"
? SUBSTREX( 'TOULOUSE', -3) && returns "USE"

FUNCTION SUBSTREX()
    LPARAMETERS tcString, tnPos, tnLen, tlAllTrim
    LOCAL lcResult, lnFor, lcBitOfString

    lcResult = ""

    *** Check Parms
    IF TYPE('tcString') = 'C' AND TYPE('tnPos') = 'N' AND (TYPE('tnLen') <> 'L' OR TYPE('tnLen') <> 'N' )
        IF tlAllTrim
            tcString = ALLTRIM(tcString)
        ENDIF
        IF tnPos < 0
            tnPos = LEN(tcString) - ABS(tnPos) + 1
        ENDIF
        DO CASE
            CASE TYPE('tnLen') = 'L'
                *** Return all from starting position if no second parm is passed
                lcResult = SUBSTR( tcString, tnPos)
            CASE tnLen > 0
                *** Standard SUBSTR() - Read left to right
                lcResult = SUBSTR(tcString, tnPos, tnLen)
            CASE tnLen < 0
                tnLen = ABS(tnLen)
                IF tnLen > tnPos
                    tnLen = tnPos
                ENDIF
                *** Read from left for starting position, read right to left for result
                lcBitOfString = SUBSTR(tcString, tnPos - tnLen + 1, tnLen)
                FOR lnFor = tnLen TO 1 STEP -1
                    lcResult = lcResult + SUBSTR(lcBitOfString, lnFor, 1)
                ENDFOR
        ENDCASE
    ENDIF
    RETURN lcResult
ENDFUNC

boyd.gif

 
Darn it! I introduced a logical error of my own... that's what I get for not looking at the code long enough.
Code:
IF TYPE('tcString') = 'C' AND TYPE('tnPos') = 'N' AND (TYPE('tnLen') <> 'L' OR TYPE('tnLen') <> 'N' )
...should read...
Code:
IF TYPE('tcString') = 'C' AND TYPE('tnPos') = 'N' AND (TYPE('tnLen') [COLOR=red]=[/color] 'L' OR TYPE('tnLen') [COLOR=red]=[/color] 'N' ) [COLOR=red]AND Type('tlAlltrim') = 'L'[/color]

Hopefully, I didn't miss anything else. <g>

boyd.gif

 
If you want to find a single character from the right as in FatSlugs initial post substr() can be used.

lcWord = 'TOULOUSE' && the word
nEnd = 4 &&number of characters from right letter

?substr(lcWord,len(allt(lcWord))-nEnd +1,1)



 
Thanks Craig,

the original idea came from PHP. There the substr function already has about that same interpretation. It differs in that the first position is 0 - as always in other languages - and a negative length is interpreted as truncation rather than reverse extraction direction. Maybe the php way is even the better idea and it would be better to adopt to this:


But the thing is, that this way you won't get reversed order strings. PHP has a seperate function for that (strrev), so it doesn't need the substr() functionality the way I defined it:


PHP has other nice functions worth porting to VFP, eg. explode, which compares roughly to ALINES, but also the opposite - implode - for which you need a loop and string concatenation in VFP:


And that's not the end...

Bye, Olaf.
 
Hi Craig!

Thanks for your input on this. I have updated the FAQ accordingly!

Neil

I like work. It fascinates me. I can sit and look at it for hours...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top