Recent

Author Topic: Help with search and repalce whole word without case sensitivity  (Read 2061 times)

zxandris

  • Full Member
  • ***
  • Posts: 169
Help with search and repalce whole word without case sensitivity
« on: November 10, 2025, 09:24:53 am »
Okay so I'm using Lazarus 4.2, and I'm trying to take a string then search and replace by whole word, but not worrying about case.  I have some functions I got from the net but they appear to be trimming somehow.  I can't for the life of me figure out how, it seems to trim like #9 #10#13 etc, but as far as I can tell it shouldn't be.  I've tried to account and it's still not working.

My functions
Code: Pascal  [Select][+][-]
  1. function IsWordChar(ch: Char): Boolean;
  2. begin
  3.   // Letters and digits are word characters. Include '_' if you want underscore to count as part of words.
  4.   Result := TCharacter.IsLetterOrDigit(ch) or (ch = '_');
  5. end;
  6.  
  7. function PosWholeWordInsensitive(const Sub, S: string; StartPos: Integer = 1): Integer;
  8. var
  9.   i, LSub, LStr: Integer;
  10.   Hay, Needle: string;
  11.   beforeOK, afterOK: Boolean;
  12. begin
  13.   Result := 0;
  14.   if (Sub = '') or (S = '') then Exit;
  15.   if StartPos < 1 then StartPos := 1;
  16.  
  17.   LSub := Length(Sub);
  18.   LStr := Length(S);
  19.   if StartPos > LStr - LSub + 1 then Exit;
  20.  
  21.   // Use Unicode-aware case folding; UpperCase is OK for many RTLs. Replace with proper casefold if available.
  22.   Hay := UpperCase(S);
  23.   Needle := UpperCase(Sub);
  24.  
  25.   i := StartPos;
  26.   while i <= LStr - LSub + 1 do
  27.   begin
  28.     if Copy(Hay, i, LSub) = Needle then
  29.     begin
  30.       // check char before match (if any)
  31.       if i = 1 then
  32.         beforeOK := True
  33.       else
  34.         beforeOK := not IsWordChar(S[i - 1]);
  35.  
  36.       // check char after match (if any)
  37.       if i + LSub - 1 = LStr then
  38.         afterOK := True
  39.       else
  40.         afterOK := not IsWordChar(S[i + LSub]);
  41.  
  42.       if beforeOK and afterOK then
  43.       begin
  44.         Result := i;
  45.         Exit;
  46.       end;
  47.     end;
  48.     Inc(i);
  49.   end;
  50. end;
  51.  

The Search and Replace
Code: Pascal  [Select][+][-]
  1. function strSearchReplaceWholeAll(const strText, strToReplace, strReplaceWith : String) : String;
  2. var
  3.    ps : Integer;
  4.    a : Integer;
  5.    rtn : String;
  6.    txtBefore, txtAfter : String;
  7. begin
  8.      rtn := strText;
  9.      if (trim(rtn)<>'') and (trim(strToReplace)<>'') then
  10.      begin
  11.           try
  12.              ps := posWholeWordInsensitive(strToReplace, rtn, ps);
  13.              while ps>0 do
  14.              begin
  15.                  txtBefore := subStr(rtn, 1, ps-1);
  16.                  txtAfter := subStr(rtn, (ps + length(strToReplace)), length(rtn));
  17.  
  18.                  if (rtn[ps-1]=#10) then
  19.                     rtn := #10 + txtBefore + strReplaceWith + txtAfter
  20.                  else if (rtn[ps-1]=#13) then
  21.                       rtn := #13 + txtBefore + strReplaceWith + txtAfter
  22.                  else if (rtn[ps-1]=#13) then
  23.                       rtn := #13 + txtBefore + strReplaceWith + txtAfter
  24.                  else if (rtn[ps-1]=#9) then
  25.                       rtn := #9 + txtBefore + strReplaceWith + txtAfter;
  26.  
  27.  
  28.                  if (rtn[ps+length(strToReplace)]=#10) then
  29.                     rtn := txtBefore + strReplaceWith + #10 + txtAfter
  30.                  else if (rtn[ps+length(strToReplace)]=#13) then
  31.                     rtn := txtBefore + strReplaceWith + #13 + txtAfter
  32.                  else if (rtn[ps+length(strToReplace)]=#9) then
  33.                       rtn := txtBefore + strReplaceWith + #9 + txtAfter
  34.                  else
  35.                      rtn := txtBefore + strReplaceWith + txtAfter;
  36.  
  37.  
  38.                  ps := ps + length(strReplaceWith);
  39.                  ps := posWholeWordInsensitive(strToReplace, rtn, ps);
  40.                  if (ps>=length(rtn)) or (ps<=0) then break;
  41.              end;
  42.           except
  43.                 //
  44.           end;
  45.      end;
  46.      result := rtn;
  47. end;
  48.  

It's probably a mess, or I'm missing something obvious but would really LOVE some help on this it's driving me insane! lol

Thanks

CJ

BlueIcaro

  • Hero Member
  • *****
  • Posts: 827
    • Blog personal
Re: Help with search and repalce whole word without case sensitivity
« Reply #1 on: November 10, 2025, 09:36:03 am »
Hello, you can use functions included in strutils unit
https://www.freepascal.org/docs-html/rtl/strutils/index-5.html

You can search for number of words with wordcount https://www.freepascal.org/docs-html/rtl/strutils/wordcount.html

You can replace a text with ReplaceText https://www.freepascal.org/docs-html/rtl/strutils/replacetext.html

Take a look to this unit, has many functions and prodedures to work with strings, and many of them has their variant for insensitive case

/BlueIcaro


Thaddy

  • Hero Member
  • *****
  • Posts: 18475
  • Here stood a man who saw the Elbe and jumped it.
Re: Help with search and repalce whole word without case sensitivity
« Reply #2 on: November 10, 2025, 10:28:05 am »
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. uses sysutils;
  3.  
  4. var
  5.   a:string = 'IoPUkIoUkIOPuk';  // <--- can be a whole file!
  6. begin
  7.   writeln(a.Replace('Io',' -Test-', [rfReplaceAll]));             //case sensitive
  8.   writeln(a.Replace('Io',' -Test-', [rfReplaceAll,rfIgnoreCase]));//case ignored.
  9. end.
It is not much simpler than that, is it?
« Last Edit: November 10, 2025, 10:32:04 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

CM630

  • Hero Member
  • *****
  • Posts: 1548
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Help with search and repalce whole word without case sensitivity
« Reply #3 on: November 10, 2025, 12:54:09 pm »
This should be working search and replace code; the Lazarus inbuilt one used to cause problems, possibly it was fixed in recent years.

https://forum.lazarus.freepascal.org/index.php/topic,26137.msg274687.html#msg274687
Лазар 4,4 32 bit (sometimes 64 bit); FPC3,2,2

avk

  • Hero Member
  • *****
  • Posts: 824
Re: Help with search and repalce whole word without case sensitivity
« Reply #4 on: November 10, 2025, 04:35:29 pm »
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. uses sysutils;
  3.  
  4. var
  5.   a:string = 'IoPUkIoUkIOPuk';  // <--- can be a whole file!
  6. begin
  7.   writeln(a.Replace('Io',' -Test-', [rfReplaceAll]));             //case sensitive
  8.   writeln(a.Replace('Io',' -Test-', [rfReplaceAll,rfIgnoreCase]));//case ignored.
  9. end.
It is not much simpler than that, is it?

This approach seems to have a small drawback: TReplaceFlags does not have the rfWholeWordsOnly flag.

... the Lazarus inbuilt one used to cause problems, possibly it was fixed in recent years ...

I also remember that String.Replace() was buggy.

jamie

  • Hero Member
  • *****
  • Posts: 7379
Re: Help with search and repalce whole word without case sensitivity
« Reply #5 on: November 10, 2025, 11:33:59 pm »
CompareText is case insensitive

Jamie


The only true wisdom is knowing you know nothing

zxandris

  • Full Member
  • ***
  • Posts: 169
Re: Help with search and repalce whole word without case sensitivity
« Reply #6 on: November 11, 2025, 10:29:05 am »
Thanks peeps,

I will look into those, I think the biggest thing is that it needs to replace whole words so 'ThisIsAString' replacing with replace would replace say 'This' which is part of the string where as I would only want to replace 'This Is a string', the 'This' in that is what I'd want to replace not the one that is part of the first.

See what I mean, I feel I'm not explaining that well but I can't think of another way of putting it.

avk

  • Hero Member
  • *****
  • Posts: 824
Re: Help with search and repalce whole word without case sensitivity
« Reply #7 on: November 11, 2025, 10:44:45 am »
It looks like you're trying to use Delphi code(uses UTF-16 strings) in Lazarus(uses UTF-8 strings).

You could try this modified version:
Code: Pascal  [Select][+][-]
  1. function IsWordChar(ch: WideChar): Boolean;
  2. begin
  3.   // Letters and digits are word characters. Include '_' if you want underscore to count as part of words.
  4.   Result := TCharacter.IsLetterOrDigit(ch) or (ch = '_');
  5. end;
  6.  
  7. function PosWholeWordInsensitive(const Sub, S: unicodestring; StartPos: Integer = 1): Integer;
  8. var
  9.   i, LSub, LStr: Integer;
  10.   Hay, Needle: unicodestring;
  11.   beforeOK, afterOK: Boolean;
  12. begin
  13.   Result := 0;
  14.   if (Sub = '') or (S = '') then Exit;
  15.   if StartPos < 1 then StartPos := 1;
  16.  
  17.   LSub := Length(Sub);
  18.   LStr := Length(S);
  19.   if StartPos > LStr - LSub + 1 then Exit;
  20.  
  21.   // Use Unicode-aware case folding; UpperCase is OK for many RTLs. Replace with proper casefold if available.
  22.   Hay := ToUpper(S);
  23.   Needle := ToUpper(Sub);
  24.  
  25.   i := StartPos;
  26.   while i <= LStr - LSub + 1 do
  27.   begin
  28.     if Copy(Hay, i, LSub) = Needle then
  29.     begin
  30.       // check char before match (if any)
  31.       if i = 1 then
  32.         beforeOK := True
  33.       else
  34.         beforeOK := not IsWordChar(S[i - 1]);
  35.  
  36.       // check char after match (if any)
  37.       if i + LSub - 1 = LStr then
  38.         afterOK := True
  39.       else
  40.         afterOK := not IsWordChar(S[i + LSub]);
  41.  
  42.       if beforeOK and afterOK then
  43.       begin
  44.         Result := i;
  45.         Exit;
  46.       end;
  47.     end;
  48.     Inc(i);
  49.   end;
  50. end;
  51.  
  52. function strSearchReplaceWholeAll(const strText, strToReplace, strReplaceWith : unicodestring) : string;
  53. var
  54.    ps : Integer;
  55.    a : Integer;
  56.    rtn : unicodestring;
  57.    txtBefore, txtAfter : unicodestring;
  58. begin
  59.      rtn := strText;
  60.      if (trim(rtn)<>'') and (trim(strToReplace)<>'') then
  61.      begin
  62.           try
  63.              ps := posWholeWordInsensitive(strToReplace, rtn, ps);
  64.              while ps>0 do
  65.              begin
  66.                  txtBefore := Copy(rtn, 1, ps-1);
  67.                  txtAfter := Copy(rtn, (ps + length(strToReplace)), length(rtn));
  68.  
  69.                  if (rtn[ps-1]=#10) then
  70.                     rtn := #10 + txtBefore + strReplaceWith + txtAfter
  71.                  else if (rtn[ps-1]=#13) then
  72.                       rtn := #13 + txtBefore + strReplaceWith + txtAfter
  73.                  else if (rtn[ps-1]=#13) then
  74.                       rtn := #13 + txtBefore + strReplaceWith + txtAfter
  75.                  else if (rtn[ps-1]=#9) then
  76.                       rtn := #9 + txtBefore + strReplaceWith + txtAfter;
  77.  
  78.  
  79.                  if (rtn[ps+length(strToReplace)]=#10) then
  80.                     rtn := txtBefore + strReplaceWith + #10 + txtAfter
  81.                  else if (rtn[ps+length(strToReplace)]=#13) then
  82.                     rtn := txtBefore + strReplaceWith + #13 + txtAfter
  83.                  else if (rtn[ps+length(strToReplace)]=#9) then
  84.                       rtn := txtBefore + strReplaceWith + #9 + txtAfter
  85.                  else
  86.                      rtn := txtBefore + strReplaceWith + txtAfter;
  87.  
  88.  
  89.                  ps := ps + length(strReplaceWith);
  90.                  ps := posWholeWordInsensitive(strToReplace, rtn, ps);
  91.                  if (ps>=length(rtn)) or (ps<=0) then break;
  92.              end;
  93.           except
  94.                 //
  95.           end;
  96.      end;
  97.      result := string(rtn);
  98. end;
  99.  

But from a performance point of view, this code is a real disaster.

Zvoni

  • Hero Member
  • *****
  • Posts: 3161
Re: Help with search and repalce whole word without case sensitivity
« Reply #8 on: November 11, 2025, 12:35:12 pm »
Why not use Regex with Word-Boundary?

TRegExpr-Unit even contains "Substitute/Replace"-Functions

https://regex101.com/r/x29RTc/2

https://regex.sorokin.engineer/tregexpr/
« Last Edit: November 11, 2025, 12:49:57 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

avk

  • Hero Member
  • *****
  • Posts: 824
Re: Help with search and repalce whole word without case sensitivity
« Reply #9 on: November 12, 2025, 07:13:46 am »
Why not use Regex with Word-Boundary?

TRegExpr-Unit even contains "Substitute/Replace"-Functions
...

IIRC, the TRegExpr that came with the FPC packages was not unicode-aware.
Has anything changed in this regard now?

Zvoni

  • Hero Member
  • *****
  • Posts: 3161
Re: Help with search and repalce whole word without case sensitivity
« Reply #10 on: November 12, 2025, 07:44:27 am »
Why not use Regex with Word-Boundary?

TRegExpr-Unit even contains "Substitute/Replace"-Functions
...

IIRC, the TRegExpr that came with the FPC packages was not unicode-aware.
Has anything changed in this regard now?
--> https://regex.sorokin.engineer/tregexpr/#unicode
Quote
Unicode

In Unicode mode, all strings (InputString, Expression, internal strings) are of type UnicodeString/WideString, instead of simple "string". Unicode slows down performance, so use it only if you really need Unicode support.

To use Unicode, uncomment {$DEFINE UniCode} in regexpr.pas (remove off).
Maybe Andrey or Alexej will chip in here.

Though i just looked into the mentioned file which came with fpc3.2.2, and i can't find the mentionend commented Define.
I found it in "uregexpr.pp" though, which INCLUDES regexpr.pas
So it's probably just either
1) inserting a {$DEFINE UniCode} at the beginning of regexpr.pas
2) a "UniCode"-Constant in Project-Options
3) include "uregexpr" in Uses instead of "regexpr" (Everyone can have a guess, what the "u" in the unit-name stands for.....)
« Last Edit: November 12, 2025, 07:54:35 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

zxandris

  • Full Member
  • ***
  • Posts: 169
Re: Help with search and repalce whole word without case sensitivity
« Reply #11 on: November 12, 2025, 01:24:06 pm »
As per RegExp, I have quite literally no idea how to use it, so any tips on how to do this in regExp would be appreciated :)

Thaddy

  • Hero Member
  • *****
  • Posts: 18475
  • Here stood a man who saw the Elbe and jumped it.
Re: Help with search and repalce whole word without case sensitivity
« Reply #12 on: November 12, 2025, 01:33:56 pm »
RexEx are not for noobs. But it can be done. Will add example later.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Zvoni

  • Hero Member
  • *****
  • Posts: 3161
Re: Help with search and repalce whole word without case sensitivity
« Reply #13 on: November 12, 2025, 05:31:00 pm »
As per RegExp, I have quite literally no idea how to use it, so any tips on how to do this in regExp would be appreciated :)
You mean besides the fact, that i posted links to an online-Regex-Tool with an example, where the online-tool even explains what it is doing,
and the official documentation of the Regexpr-Unit?
« Last Edit: November 12, 2025, 05:33:41 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

zxandris

  • Full Member
  • ***
  • Posts: 169
Re: Help with search and repalce whole word without case sensitivity
« Reply #14 on: November 13, 2025, 02:11:55 pm »
Ahh, I didn't so much mean the class, as actual regexp. i.e. how to use regex to do things.  I will read the site as per the component but the actual regex I don't so much know a thing about how to use it I'm afraid.  Shockingly enough, so far, I've not found a need for it, but I suspect I have one now.

As per RegExp, I have quite literally no idea how to use it, so any tips on how to do this in regExp would be appreciated :)
You mean besides the fact, that i posted links to an online-Regex-Tool with an example, where the online-tool even explains what it is doing,
and the official documentation of the Regexpr-Unit?

 

TinyPortal © 2005-2018