Replace match with Stringtheory

I need to replace the string matching a regex with another string. The new string is created by a function, which I only want to call it if there is a match. This is my current code, I wonder if there is a simpler or more efficient way to do the replace:

  st.FindMatchPosition(regex,starts,ends,Match:Regular,TRUE)
  IF starts AND ends 
    st.SetValue( st.Slice(1,starts-1) & createnewvalue() & st.Slice(ends+1) )
  END

@vitesse @Bruce Would it be too much work to add methods .ReplaceMatch(...) and .ReplacePosition(...)? If there isn’t something similar already that I missed. Thanks in advance for your comments.

Before my system and backups got wiped a few weeks ago I had code that did this and it worked in the templates as well.

I seem to remember posting some code on here which would help you get the start and finish positions using strpos. I think its written in clarion but it might also be a template language code example.

Fwiw

Hi Carlos

well that’s a coincidence - I wrote code to do this over the weekend and just yesterday sent it to Bruce for consideration for inclusion in a future version of ST along with a bunch of other stuff.

I called the new method ReplaceSlice and the comment in the code says:

!----------------------------------------------------------------------------------
! Sets the value of the specified region within the string to the passed string.
! Unlike setSlice() which either truncates or space fills the new value to fit the
! existing size of the slice, replaceSlice() will expand or contract the slice
! within the value string to exactly fit the newValue.

if you scroll down the in code at

you will see some code of the form:

 st.replace(st.slice(srcStart,srcEnd),'replacementString',1,srcStart,srcEnd)

actually the final parameter is redundant and it could have just been written:

 st.replace(st.slice(srcStart,srcEnd),'replacementString',1,srcStart)

with the new method replaceSlice this would instead look like:

 st.replaceSlice(srcStart,srcEnd,'replacementString')

and would be more efficient as it is not doing a “dummy search” before the replace.

as regards your current code

  st.FindMatchPosition(regex,starts,ends,Match:Regular,TRUE)
  IF starts AND ends 
    st.SetValue( st.Slice(1,starts-1) & createnewvalue() & st.Slice(ends+1) )
  END

I suggest changing the test so instead have

  st.FindMatchPosition(regex,starts,ends,Match:Regular,TRUE)
  IF starts AND ends >= starts
    st.SetValue( st.Slice(1,starts-1) & createnewvalue() & st.Slice(ends+1) )
  END

or use the replace code with a dummy search which might be a little faster:

IF starts AND ends >= starts 
  st.replace(st.slice(starts,ends),createnewvalue(),1,starts)
END

then if/when replaceSlice becomes available, instead use:

IF starts AND ends >= starts 
 st.replaceSlice(starts,ends,createnewvalue())
END

if you are keen to try replaceSlice now then (if Bruce is agreeable) I could send you my current version by PM.

one thing to note is that your st.FindMatchPosition will find the SMALLEST minimal match.

hopefully that is what you are after (and not the maximal “leftmost longest” match).

if you are after that “leftmost longest” match, have a look at the code here which includes StrPosAndLen which returns position and minimum and maximum length of string matched against regex There are a lot of “gotchas” with strPos and this works around them.

hth and cheers

Geoff R

1 Like

Hi Richard

I think this may be related to the StrPosAndLen code I mentioned in my previous message - I recall we had several conversations about this over a couple of years and it went through a few iterations before that version.

cheers

Geoff R

Hi Geoff

Excellent!

That’s a better name.

Thanks! That’ll work for now, and hopefully, in a future version of ST, I can switch to ReplaceSlice.

Yes, in this case, but I’ll look into the other code you posted since I might need “greedy” matches in the future.

Thanks again your comments and insights.

Regards,

Carlos

1 Like

thanks Carlos

if you were after a tiny bit more speed now while waiting for ReplaceSlice, you could use a little “inside knowledge” and alter

to instead be

IF starts AND ends >= starts AND ends <= st._DataEnd
  st.replace(st.valuePtr[starts : ends],createnewvalue(),1,starts)
END

“purists” probably would not approve as here we are not using the official public interfaces.

cheers again

Geoff R

I had started mirroring the extra regex functionality microsoft provides in dotnet regex so theres no reason why capesoft or softvelocity cant mirror the dotnet regex functionality either.

Nice, thank you! I didn’t know valuePtr was available and public. It’s actually documented in the Upgrading section, so the “purists” should be happy :slight_smile: .