is there any string replacement function in FB

General FreeBASIC programming questions.
zydon
Posts: 31
Joined: Nov 02, 2005 18:42

is there any string replacement function in FB

Postby zydon » Dec 27, 2005 9:19

I'm looking for ReplaceSubStr$() or VB's Replace$() function. Is there one in FB? Or is there anyone write custom UDF for it?

Thanks in advance.
Andrew Collins
Posts: 18
Joined: Aug 02, 2005 1:34

Postby Andrew Collins » Dec 27, 2005 14:02

Use INSTR and MID$ like so

Code: Select all

text$ = "abc 123"
PRINT text$               'returns "abc 123"

start  = INSTR(text$, "1") ' find the 1 or whatever you want to find

Newtext$= "456"

MID(text$, start, LEN(Newtext$)) = Newtext$

PRINT text$              'displays "abc 456"


This doesn't work exactly like vb's replace but with some foresight in your coding it could work for ya.
hippy
Posts: 84
Joined: Nov 04, 2005 18:13
Location: UK

Postby hippy » Dec 27, 2005 15:38

This may help set you on your way. Code taken from a non-FB project so it could be made more FB-like ...

Code: Select all

Declare Function ReplaceFirst$(source$,match$,replacement$)
Declare Function ReplaceAll$(source$,match$,replacement$)

l$ = "XXX"
l$ = ReplaceAll$(l$,"X","-X-")
Print l$
End

Function ReplaceFirst$(source$,match$,replacement$)
Dim t$
Dim i%
  t$ = source$
  i% = Instr(t$,match$)
  If i% > 0 Then
    t$ = Left$(t$,i%-1)+Replacement$+Right$(t$,Len(t$)-i%-Len(match$)+1)
  End If
  ReplaceFirst$ = t$
End Function

Function ReplaceAll$(source$,match$,replacement$)
Dim t$
Dim i%
  t$ = source$
  i% = Instr(t$,match$)
  While i% > 0
    t$ = Left$(t$,i%-1)+Replacement$+Right$(t$,Len(t$)-i%-Len(match$)+1)
    i% = Instr(i%+Len(replacement$),t$,match$)
  wend
  ReplaceAll$ = t$
End Function
zydon
Posts: 31
Joined: Nov 02, 2005 18:42

Postby zydon » Dec 27, 2005 16:47

Thanks Andrew and hippy. I finally make my own version of ReplaceSubStr$() after learning from Andrew's techniques, but with a combination of instr() and len() . here is mine:

Code: Select all

option escape

function ReplaceSubStr( src as string, _
                        old as string, _
                        rep as string ) as string
CheckAgain:
    dim isfoundat as integer = instr(src,left(old,1))
    if (isfoundat) then
       src = left(src,isfoundat-1) + rep + _
             right(src,len(src)-(isfoundat+len(old)-1))
       isfoundat = 0
       goto CheckAgain
    end if
    function = src
end function

' VB compatible?
#define replace replacesubstr


'--- example of uses ---
dim txt as string
    txt = "abc 123 def 123 ghi"

print "txt = ";txt
print
txt = ReplaceSubStr$(txt,"123","456789")
print "txt = ReplaceSubStr$(txt,\"123\",\"456789\")"
print "    = ";txt
print
print "'Lets make a list out of it"
print "txt = Replace$(txt,\" \",chr$(10)+chr$(13))"
txt = Replace$(txt," ",chr$(10)+chr$(13))
print
print "Result:"
print txt
print
print "Press any key to continue..."
sleep


Thanks again.
coderJeff
Site Admin
Posts: 3170
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Postby coderJeff » Dec 27, 2005 21:11

Function causes an infinate loop if the replacement string contains the substring you are looking for.
Example:

Code: Select all

Print ReplaceSubStr("Test","e","New")

I would expect this to print "TNewst". Instead, the function keeps finding and replacing the "e".
Also, you are modifying the variable 'src' in your function. Is this really what you intended?

Code: Select all

Dim s As String, d As String
s = "This is a test"
d = ReplaceSubStr(s," is "," was ")
Print "Before = "; s
Print "After  = "; d

This prints out:

Code: Select all

Before = This was a test
After = This was a test
DrV
Site Admin
Posts: 2116
Joined: May 27, 2005 18:39
Location: Midwestern USA
Contact:

Postby DrV » Dec 27, 2005 21:27

This is how I would do it:

Code: Select all

function ReplaceSubStr( src as string, _
                        old as string, _
                        rep as string ) as string
   dim isfoundat as integer
   dim ret as string

   isfoundat = 1
   ret = src
   
   do
      isfoundat = instr(isfoundat, ret, old)
      
      if isfoundat = 0 then exit do
      
      ret = left(ret, isfoundat - 1) + _
            rep + _
            mid(ret, isfoundat + len(old))
      
      isfoundat += len(rep)
   loop
   
   return ret
   
end function

Not tested too thoroughly, but it worked in the case pointed out by coderJeff. It also does not modify src.
zydon
Posts: 31
Joined: Nov 02, 2005 18:42

Postby zydon » Dec 28, 2005 7:41

Thanks DrV. The improvement you've made is very solid and secure. A lots more I have to learn from you guys. ;)
coderJeff
Site Admin
Posts: 3170
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Postby coderJeff » Dec 28, 2005 8:38

DrV:
Yes, very nice. Except for the variable names, I have that function practically line for line in my code library for VB5. Works perfectly in all cases under FB.

However, I can't say the same for VB/QB. In VB/QB Instr(s,a,b) returns s if b="", not zero (0) as you would expect. In otherwords Instr() has bugs under VB/QB.

freeBASIC makes me happy ...
jonathanbrickman0000
Posts: 189
Joined: Dec 23, 2005 21:16
Location: Topeka, Kansas, USA
Contact:

Postby jonathanbrickman0000 » Jan 28, 2006 22:57

Me too. DrV, you just saved me a lot of work.
stylin
Posts: 1253
Joined: Nov 06, 2005 5:19

Postby stylin » Jan 29, 2006 9:42

I would take a much more compact approach to the problem. Also, a little error checking wouldn't hurt the function's efficiency either:

Code: Select all

function ReplaceSubStr( srcStr as string, subStr as string, _
                        rep as string ) as string
    if( srcStr="" or subStr="" ) then return srcStr
   
    dim as string result => srcStr
    dim as integer subStrFoundAt => instr( 1, result, subStr )
   
    while( subStrFoundAt > 0 )
        result = left( result, subStrFoundAt-1 ) + rep + _
                       mid( result, subStrFoundAt+len(subStr) )
        subStrFoundAt = instr( subStrFoundAt+len(rep), _
                               result, subStr )
    wend

    return result
end function


Note that you can bail if src or subStr are passed as bogus values, eliminating the need to copy the (possibly expensive) source string. Passing a string by value should work as expected in the near future, so the initial explicit copy will be able to be avoided anyway. line-continuations make this particular code rather ugly, and I only include them for the sake of the forum)
jonathanbrickman0000
Posts: 189
Joined: Dec 23, 2005 21:16
Location: Topeka, Kansas, USA
Contact:

Postby jonathanbrickman0000 » Jan 29, 2006 13:59

What in the WORLD is =>, as in "dim as string result => srcStr" ???! I have never seen that before. Also, it's not in the Operators List (http://www.freebasic.net/wiki/wikka.php?wakka=CatPgOperators) !
stylin
Posts: 1253
Joined: Nov 06, 2005 5:19

Postby stylin » Jan 29, 2006 17:25

Here's a whole thread: linky

And I'm sure not being in the wiki is just an oversight.
Eclipzer
Posts: 432
Joined: Oct 01, 2005 10:50
Location: Maryland
Contact:

Postby Eclipzer » Oct 16, 2008 9:40

I wrote a string replacement function, only to find this lovely thread. After reviewing the various submissions here, I modified my own to be a bit more compact and complete.

Code: Select all

' =============================================================================
'          Name: str_replace (10.16.08)
'       Returns: string
'    Parameters: (text,subString,newString)
'          text:
'     subString:
'     newString:
' -----------------------------------------------------------------------------
'   Description: Return a string with each instance of subString in text
'                replaced with newString.
'      Comments:
' =============================================================================
  function str_replace(text as string,subString as string,newString as string) as string
       
    if (text="") or (subString="") then return text
     
    dim as string  result=text 
    dim as integer sublen=len(subString),newlen=len(newString)
    dim as integer match=1-newlen
   
    do     
      match=instr(match+newlen,result,subString)
      if match=0 then exit do
      result=left(result,match-1) & newString & mid(result,match+sublen)     
    loop
   
    return result
     
  end function


Two things to note. First, I only make a single call to INSTR. Most approaches require an initial call outside the loop, with subsequent calls within the loop. In general, I feel this type of code redundancy makes future modifications more difficult. Second, the sub-string and replacement string lengths are pre-calced outside the loop, for speed.

These sorts of problems make me wish FB supported explicit assignment and equivalence symbols, which would reduce the loop to:

Code: Select all

 do while match=instr(match+newlen,result,subString) 'assign value to match, then test it
   result=left(result,match-1) & newString & mid(result,match+sublen)     
 loop
PaulSquires
Posts: 868
Joined: Jul 14, 2005 23:41

Postby PaulSquires » Oct 16, 2008 13:13

Code: Select all

If (text="") Or (subString="") Then Return text


I don't know how optimized FB is, but "in the old days" doing a string compare for length is slower than a LEN().

Code: Select all

If Len(text)=0 Or Len(subString)=0 Then Return text
Sisophon2001
Posts: 1704
Joined: May 27, 2005 6:34
Location: Cambodia, Thailand, Lao, Ireland etc.
Contact:

Postby Sisophon2001 » Oct 16, 2008 13:49

This is mine. Looks like we are all re-inventing the same thing, which makes me think it should be an packaged as a built in function in a name space, along with other handy string functions. Additions to "vbcompat.bi"?

Garvan

Code: Select all

 #include once "crt.bi"
''------------------------------------------------------------------------------
''
'' function replace(parg1 as zstring ptr, parg2 as zstring ptr, parg3 as zstring ptr) as string
''
'' Purpose  : Replaces parg2 with parg3 in parg1
''
'' History  : Modified from BCX Code 2005.3.1 - GOK
''
''------------------------------------------------------------------------------
function replace(parg1 as zstring ptr, parg2 as zstring ptr, parg3 as zstring ptr) as string
    dim as string retstr
    dim as ubyte ptr p, q, r
    dim as ubyte empty = 0
    dim as integer lparg2, lparg3, lretstr = 0, delta
   
    if *parg1 = "" then return ""
    if *parg2 = "" then return *parg1
    if *parg3 = "" then parg3 = @empty
   
    lparg2 = strlen(parg2)
    lparg3 = strlen(parg3)

    p = parg1
    q = strstr(p, parg2)
    if q = NULL then return *parg1
    while q <> NULL
        lretstr = lretstr + (q - p) + lparg3
        p = q + lparg2
        q = strstr(p,parg2)
    wend

    lretstr += strlen(p)

    retstr = string(lretstr, " ")
    r = strptr(retstr)
    p = parg1
    q = strstr(p, parg2)

    while q <> NULL
        delta = (q - p)
        strncpy(r, p, delta)
        r += delta
        strcpy(r, parg3)
        r += lparg3
        p = q + lparg2
        q = strstr(p,parg2)
    wend

    strcpy(r,p)
    return retstr
end function


EDIT: added missing double quote.
EDIT: changed to zstring
Last edited by Sisophon2001 on Oct 19, 2008 1:52, edited 3 times in total.

Return to “General”

Who is online

Users browsing this forum: No registered users and 3 guests