String Function replace() - Replace all occurrences of one character with another

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
dmontaine
Posts: 23
Joined: Mar 15, 2018 7:13

String Function replace() - Replace all occurrences of one character with another

Post by dmontaine »

String function replace() with example program

Code: Select all

'Program: ReplaceFunctionExample
' This program shows how the included 'replace' function
' converts all instances of one character in a string to another

'==================================================
' replace function
'==================================================

' copyright 2022 Donald S Montaine
' released under the Creative Commons CC-BY license

function replace(byval SearchString as string,byval FromChar as string,byval ToChar as string) as string
   if SearchString = "" or FromChar = ""  or ToChar = "" then return ""
   
   dim CurrChar as string						
   dim OutString as string						'
   for Ctr as integer = 1 to len(SearchString)
      CurrChar=mid(SearchString,Ctr,1)
      if CurrChar = FromChar then
         OutString += ToChar
      else
         OutString += CurrChar
      end if
   next
   Return OutString
end function

'==================================================
' Main Program
'==================================================
' Replaces all occurances of "|" with ","

width 80,24
dim InputString  as string = "a|b|c|d|e|f|g"
dim OutputString as string = replace(InputString,"|",",")

locate 1,1
print "Replace() function example program"
locate 3,5
print "The original string = " + InputString
locate 4,5
print "The modified string = " + OutputString

locate 6,1
print "Press any key to exit " ;
sleep
Last edited by dmontaine on Jul 20, 2022 4:01, edited 1 time in total.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: String Function - Replace all occurrences of one character with another

Post by fxm »

More concise and faster procedure:
- Since the string is passed by value, we can work directly on it and therefore not recopy the unchanged characters (the original string is not modified).
- Since we are working character by character, we can use the string index operator '[]' (instead of 'mid(...,1)') which is faster.

Code: Select all

function replace(byval SearchString as string,byval FromChar as string,byval ToChar as string) as string
   if SearchString = "" or FromChar = ""  or ToChar = "" then return ""
   
   for Ctr as integer = 0 to len(SearchString) - 1
      if SearchString[Ctr] = asc(FromChar) then
         SearchString[Ctr] = asc(ToChar)
      end if
   next
   Return SearchString
end function
Last edited by fxm on Jul 19, 2022 14:54, edited 1 time in total.
Reason: Update: Forgot first character of string for test/replacement.
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: String Function - Replace all occurrences of one character with another

Post by SARG »

Even faster :)

- Keep FromChar and ToChar as byref parameters. It avoids creating tempo string variables.
- Use len()=0 instead comparison with an empty string
- Use tempo variables containing asc() to avoid useless calls in the loop

Code: Select all

function replace(byval SearchString as string,FromChar as string,ToChar as string) as string
   if len(SearchString) = 0 or len(FromChar) = 0  or len(ToChar) = 0 then return ""
   dim as integer fc=asc(FromChar), tc=asc(ToChar)
   for Ctr as integer = 1 to len(SearchString) - 1
      if SearchString[Ctr] = fc then
         SearchString[Ctr] = tc
      end if
   next
   Return SearchString
end function
angros47
Posts: 2324
Joined: Jun 21, 2005 19:04

Re: String Function - Replace all occurrences of one character with another

Post by angros47 »

The variables fc and tc should be of unsigned byte type, to make it even faster
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: String Function - Replace all occurrences of one character with another

Post by SARG »

angros47 wrote: Jul 18, 2022 10:12 The variables fc and tc should be of unsigned byte type, to make it even faster
Not true
- gas32 there is one more instruction when moving asc() to ubyte variable as asc() returns a long. The rest is same number of instructions.
- gas64 more instructions inside the loop when ubytes are used.

All the tests are always done with LONG/INTEGER32 (32bit) and INTEGER64 (64bit)

I didn't check with gcc.
dmontaine
Posts: 23
Joined: Mar 15, 2018 7:13

Re: String Function - Replace all occurrences of one character with another

Post by dmontaine »

Here is the modified test program implementing most of the suggestions made. Thank you. The only suggestion I didn't include was passing variables by reference. I avoid global variables and byref parameters because they decrease encapsulation. Just my own personal coding fetish.

Code: Select all

'Program: ReplaceFunctionExample
' This program shows how the included 'replace' function
' converts all instances of one character in a string to another

'==================================================
' replace function
'==================================================

function replace(byval SearchString as string,byval FromChar as string,byval ToChar as string) as string
   if len(SearchString) = 0 or len(FromChar) = 0  or len(ToChar) = 0 then return ""
   dim fc as integer = asc(FromChar)
   dim tc as integer = asc(ToChar)
   for Ctr as integer = 0 to len(SearchString) - 1
      if SearchString[Ctr] = fc then SearchString[Ctr] = tc      
   next
   Return SearchString
end function

'==================================================
' Main Program
'==================================================
' Replaces all occurances of "|" with ","

width 80,24
dim InputString  as string = "a|b|c|d|e|f|g"
dim OutputString as string = replace(InputString,"|",",")

locate 1,1
print "Replace() function example program"
locate 3,5
print "The original string = " + InputString
locate 4,5
print "The modified string = " + OutputString

locate 6,1
print "Press any key to exit " ;
sleep
Last edited by dmontaine on Jul 19, 2022 15:11, edited 1 time in total.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: String Function - Replace all occurrences of one character with another

Post by dodicat »

SARG
gas64 seems to duplicate at compile time
Also two different datatypes out, 64 and 32 bits gas64 or not.

Code: Select all

#cmdline "-gen gas64"

   #macro macro1(S1,S2)
   scope
   var n1=asc(S1),n2=asc(S2)
   #print typeof(n1)
   #print typeof(n2)
   print n1,n2
   end scope
   #endmacro


   dim as string F="0"
   macro1(F,"1")
   sleep
   
    
Gas64:

Code: Select all

Compiler output:
ULONG
UINTEGER
ULONG
UINTEGER
 
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: String Function - Replace all occurrences of one character with another

Post by SARG »

dodicat wrote: Jul 18, 2022 23:04 gas64 seems to duplicate at compile time
It should be due to #cmdline "-gen gas64" restarting the compilation.
What version of fbc do you use ? With 1.10 only one time.


asc(F) calls fb_asc() which returns a ULONG.
asc("F") no need to call fb_asc() as value known at compile time and a UINTEGER is used
Obvioulsy no real difference on 32bit but on 64bit ......
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: String Function - Replace all occurrences of one character with another

Post by dodicat »

Tested on stw build 2022-06-24
FreeBASIC Compiler - Version 1.10.0 (2022-06-24), built for win64 (64bit)
OK, no duplication.
(Should've done that to begin with!)
dmontaine
Posts: 23
Joined: Mar 15, 2018 7:13

Re: String Function - Replace all occurrences of one character with another

Post by dmontaine »

In the responses, the for statement had a -1 added to the end. Both the original code and the changed code work. What I don't understand is why.
Just looking at it, it seems that the last character in the string should never be accessed as len(SearhString) returns the proper length of the string.

for Ctr as integer = 1 to len(SearchString) - 1
if SearchString[Ctr] = fc then SearchString[Ctr] = tc
next
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: String Function - Replace all occurrences of one character with another

Post by fxm »

fxm wrote: Jul 18, 2022 5:14 More concise and faster procedure:
- Since the string is passed by value, we can work directly on it and therefore not recopy the unchanged characters (the original string is not modified).
- Since we are working character by character, we can use the string index operator '[]' (instead of 'mid(...,1)') which is faster.

Code: Select all

function replace(byval SearchString as string,byval FromChar as string,byval ToChar as string) as string
   if SearchString = "" or FromChar = ""  or ToChar = "" then return ""
   
   for Ctr as integer = 0 to len(SearchString) - 1
      if SearchString[Ctr] = asc(FromChar) then
         SearchString[Ctr] = asc(ToChar)
      end if
   next
   Return SearchString
end function
See my post updated: Forgot first character of string for test/replacement:
'for Ctr as integer = 1 = 0 to len(SearchString) - 1'
(the string index operator uses a zero-based offset from the first character)
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: String Function replace() - Replace all occurrences of one character with another

Post by fxm »

We can also use 'INSTR' + 'MID (Statement)' to do the job:

Code: Select all

function replace(byval SearchString as string,byval FromChar as string,byval ToChar as string) as string
   if len(SearchString) = 0 or len(FromChar) = 0  or len(ToChar) = 0 then return ""
   dim location as integer = 0
   do
       location = instr(location + 1,SearchString,FromChar)
       if location > 0 then mid(SearchString,location,1) = ToChar else exit do
   loop
   Return SearchString
end function
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: String Function replace() - Replace all occurrences of one character with another

Post by deltarho[1859] »

@dmontaine

Berfore going on a blitz to write more string procedures than we can shake a stick at, have a look here. PaulSquires wrote a bunch of them in 2015.

Some of them will benefit from the tips above. However, don't get carried away with performance. Unless we go past a procedure, many times and/or we have a large search string, then the execution time will be in the microsecond domain so trying to boost performance would be a waste of time.
Makoto WATANABE
Posts: 231
Joined: Apr 10, 2010 11:41
Location: Japan
Contact:

Re: String Function replace() - Replace all occurrences of one character with another

Post by Makoto WATANABE »

Thank you for telling me the string replacement function.

I would like to replace strings of Japanese ASCII double byte characters.

Print "The modified string = " + Replace(InputString,"愛","藍")

Please teach me how to modify this function to work with 2-byte characters.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: String Function replace() - Replace all occurrences of one character with another

Post by fxm »

This 'replace()' function version works regardless of the size of the sub-string to be replaced and the size of the replacing sub-string:

Code: Select all

function replace(byval SearchString as string,byval FromChar as string,byval ToChar as string) as string
   if len(SearchString) = 0 or len(FromChar) = 0  or len(ToChar) = 0 then return ""
   dim location as integer = 1 - len(ToChar)
   do
       location = instr(location + len(ToChar),SearchString,FromChar)
       if location > 0 then
           SearchString = left(SearchString,location - 1) & ToChar & mid(SearchString,location + len(FromChar))
       else
           exit do
       end if
   loop
   Return SearchString
end function
Post Reply