Help with function that can replace a part of a string sentence to another

Hello Guys,

I'd like a function where could replace a block of my text for another character.

See the example through this sentence:


"Is my sister  working with my father @at her mother's house@?"

as you can see, I have two AT (@) in my sentence, the simbol indicates the begining and the end block that must be replaced with another simbol, maybe the question mark "?", then, the sentence must be:

Is my sister working with my father ?? ?? ???????? ??????

As you can see, the space between the words must exist as the original string block.

Thanks
LVL 1
hidrauAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

KimputerCommented:
Here's the code. Please note, I expect the input to conform, so no code checking for 2 times @. If one, or 3 @ signs, it could lead to unpredictable results. With one @ sign, it just gets deleted, with 3, it just functions with the first two, leaving the third there.
Also, inputting this code didn't accept the "if original[ i ] = ' ' then" in the code without the spaces, so remove the spaces after and before the brackets.


function TForm1.customreplace(original:String):String;
var i: integer;
begin
     customreplace := leftstr(original,pos('@', original)-1);

     for i := (pos('@', original) + 1) to (pos('@', original) + pos('@',rightstr(original,length(original) - pos('@',original)))-1) do
          begin
          if original[ i ] = ' '  then
              customreplace := customreplace + ' '
          else
              customreplace := customreplace + '?';
          end;

     customreplace := customreplace + rightstr(original,length(original) - (pos('@', original) + pos('@',rightstr(original,length(original) - pos('@',original)))));

end;

Open in new window

0
Ephraim WangoyaCommented:
try

uses StrUtils;
....

function ReplaceText(const AText: string): string;
var
  Start, Stop: Integer;
  Repls: char;
  Temp, Filler: string;
begin
  Result := AText;
  Start := Pos('@', AText);
  if Start > 0 then
  begin
    Stop := PosEx('@', AText, Start+1);
    if (Stop > 0) and (Length(AText) > Stop) then
    begin
      Repls := AText[Stop+1];
      Temp := Copy(AText, Start, Stop-Start+2);
      for Start := 2 to Length(Temp) -2 do
        if Temp[Start] = '@' then
          Continue
        else if Temp[Start] > #32 then
          Filler := Filler + Repls
        else
          Filler := Filler + ' ';
      Result := AnsiReplaceText(Result, Temp, Filler);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  CTest = 'Is my sister  working with my father @at her mother''s house@?';
begin
  ShowMessage(ReplaceText(CTest));
end;

Open in new window

0
hidrauAuthor Commented:
Hello,

I forgot to tell that sometimes I have a sentence with two pair of @, for example:

That man is @working@ with my uncle at my mother's house and she is @cooking a delicious@ feijoada.

Then, the sentence must be:

That man is ????????? with my uncle at my mother's house and she is ??????? ? ??????? feijoada.

Maybe it would be great if the function could recognize how many pair of symbol I have in my sentence and it must replace the pairs.

thanks
0
CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

KimputerCommented:
Again, if by accident you input uneven number of @ characters, the last will just disappear.


function TForm1.customreplace(original:String):String;
var i: integer;
begin

     customreplace := leftstr(original,pos('@', original)-1);

     for i := (pos('@', original) + 1) to (pos('@', original) + pos('@',rightstr(original,length(original) - pos('@',original)))-1) do
          begin
          if original[ i ] = ' '  then
              customreplace := customreplace + ' '
          else
              customreplace := customreplace + '?';
          end;

     customreplace := customreplace + rightstr(original,length(original) - (pos('@', original) + pos('@',rightstr(original,length(original) - pos('@',original)))));
     if pos('@', customreplace) > 0 then
        customreplace:=customreplace(customreplace);

end;

Open in new window

0
aikimarkCommented:
what version of Delphi are you using?  The answer will depend on whether you will use TPerlRegEx or TRegExReplace.

I would probably use the regular expression object to perform the replacement.  This pattern will give you the matches of the '@' delimited text
'@([^@]*)@'

Iterate the matches, using '[\w]' as your pattern, replacing with '?'

Then, use the Delphi StringReplace() function to replace all the '@' with '' to get rid of the delimiters.
0
Sinisa VukSoftware architectCommented:
Please keep it simple:
function ReplaceWords(sText: String; sDelimitChar, cWith: Char): String;
var
  i: Integer;
  bInWord: Boolean;
begin
  Result := '';
  bInWord := False;

  for i := 1 to Length(sText) do
  begin
    if sText[i] = sDelimitChar then
      bInWord := not bInWord
    else
    begin
      if bInWord and (Ord(sText[i]) > 32) then
        Result := Result + cWith
      else
        Result := Result + sText[i];
    end;
  end;
end;


//  Edit2.Text := ReplaceWords(Edit1.Text, '@', '?');

Open in new window

0
Pierre CorneliusCommented:
Here is a working demo:

.pas source
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    tbInput: TLabeledEdit;
    tbSymbol: TLabeledEdit;
    tbResult: TLabeledEdit;
    tbChar: TLabeledEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function ReplaceBetweenSymbol(Atext:string; Symbol, replace_char: char):string;
var i,len: integer;
    replacing: boolean;
begin
  result:= '';
  replacing:= false;
  len:= length(AText);
  for i := 0 to len-1 do
  begin
    if (AText[i+1] = Symbol)
      then Replacing:= not replacing
      else begin
        if replacing
          and not (AText[i+1]=' ') //ignore spaces
          then result:= result + replace_char
          else result:= result + AText[i+1];
      end;
  end; 
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  tbResult.Text:= ReplaceBetweenSymbol(tbInput.Text, tbSymbol.Text[1], tbChar.Text[1]);
end;

end.

Open in new window


.dfm source
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 197
  ClientWidth = 377
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object tbInput: TLabeledEdit
    Left = 40
    Top = 24
    Width = 313
    Height = 21
    EditLabel.Width = 56
    EditLabel.Height = 13
    EditLabel.Caption = 'Input string'
    TabOrder = 0
  end
  object tbSymbol: TLabeledEdit
    Left = 40
    Top = 64
    Width = 103
    Height = 21
    EditLabel.Width = 98
    EditLabel.Height = 13
    EditLabel.Caption = 'Replacement symbol'
    MaxLength = 1
    TabOrder = 1
    Text = '@'
  end
  object tbResult: TLabeledEdit
    Left = 40
    Top = 152
    Width = 313
    Height = 21
    EditLabel.Width = 60
    EditLabel.Height = 13
    EditLabel.Caption = 'Result string'
    TabOrder = 2
  end
  object tbChar: TLabeledEdit
    Left = 149
    Top = 64
    Width = 113
    Height = 21
    EditLabel.Width = 111
    EditLabel.Height = 13
    EditLabel.Caption = 'Replacement character'
    MaxLength = 1
    TabOrder = 3
    Text = '?'
  end
  object Button1: TButton
    Left = 40
    Top = 104
    Width = 75
    Height = 25
    Caption = 'Replace'
    TabOrder = 4
    OnClick = Button1Click
  end
end

Open in new window



I'm using RAD XE3 so in my case string is a Unicode string.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Geert GOracle dbaCommented:
oracle is probably the most powerful database in the world.
and it's probably capable of doing it all in 1 select statement.

i had to use some recursion and some nesting but it works ...
with data as   
  (select 'That man is @working@ with my uncle at my mother''s house and she is @cooking a delicious@ feijoada.' line from dual)
select 'default line ' info, line, '' subst from data d1
union all
select 'number of matches: @*@', to_char(regexp_count(line, '@{1}([^@]+)@{1}', 1, 'in')), '' from data d1
union all
select 'match '||n||': ', regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in'), '' from data d1,
  (select level n from data d2 connect by level <=  regexp_count(line, '@{1}([^@]+)@{1}', 1, 'in')) x1
union all
select 'match '||n||' replacements of character with ?', regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in'), 
  regexp_replace(regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in', 1), '\w', '?', 1, 0, 'i')
  from data d1,
  (select level n from data d2 connect by level <=  regexp_count(line, '@{1}([^@]+)@{1}', 1, 'in')) x1
union all
select 'replaced in original string: ', d3.line, 
  regexp_replace(nvl(lag(regexp_replace(d3.line, d4.line, d4.subst)) over (order by 1), d3.line), d4.line, d4.subst) from data d3,
  (
  select n, regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in') line, 
    regexp_replace(regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in', 1), '\w', '?', 1, 0, 'i') subst
  from data d1,
  (select level n from data d2 connect by level <=  regexp_count(line, '@{1}([^@]+)@{1}', 1, 'in')) x1) d4
connect by level < d4.n;

Open in new window


i cut the statement up in several pieces so you'd be able to follow... somewhat
i admit, it's rather complex ... :)
output.jpg
0
Geert GOracle dbaCommented:
the utlimate statement can be reduced a little :

with data as   
  (select 'That man is @working@ with my uncle at my mother''s house and she is @cooking a delicious@ feijoada.' line from dual),
  substs as (
  select n, d3.line, 
    regexp_replace(nvl(lag(regexp_replace(d3.line, d4.line, d4.subst)) over (order by 1), d3.line), d4.line, d4.subst) subst,
    max(n) over (partition by d3.line) nn
  from data d3,
  ( select n, regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in') line, 
    regexp_replace(regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in', 1), '\w', '?', 1, 0, 'i') subst
  from data d1,
  (select level n from data d2 connect by level <=  regexp_count(line, '@{1}([^@]+)@{1}', 1, 'in')) x1) d4)
select line, subst 
from substs
where n = nn;

Open in new window


doing this on a table yourtable with a column line holding the text:

with data as   
  (select line from yourtable),
  substs as (
  select n, d3.line, 
    regexp_replace(nvl(lag(regexp_replace(d3.line, d4.line, d4.subst)) over (order by 1), d3.line), d4.line, d4.subst) subst,
    max(n) over (partition by d3.line) nn
  from data d3,
  ( select n, regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in') line, 
    regexp_replace(regexp_substr(line, '@{1}([^@]+)@{1}', 1, n, 'in', 1), '\w', '?', 1, 0, 'i') subst
  from data d1,
  (select level n from data d2 connect by level <=  regexp_count(line, '@{1}([^@]+)@{1}', 1, 'in')) x1) d4)
select line, subst 
from substs
where n = nn;

Open in new window

0
Pierre CorneliusCommented:
@Geert
I did not see anything in the question about a sql solution. Am I missing something? I was under the impression he was asking for a delphi function to do the parsing.
0
aikimarkCommented:
@Geert

Thanks for posting that.  I wasn't paying attention when Oracle introduced regular expression support back in 2003 (version 10g feature).  I learned something new.

===========
@hidrau

Where are your strings being stored? (file, database, WS, other)
0
Geert GOracle dbaCommented:
PierreC
I wasn't aware that looking at a problem should only be done from 1 angle...

you can ride through a one-way street with more than only a car ...
walking is also possible, a bullet train might be a little over
0
Geert GOracle dbaCommented:
@aikimark,
congrats on learning something
0
aikimarkCommented:
@Geert

Thank you.  And thanks, again, for posting it.

I'm probably doing an advanced regular expressions presentation at the upcoming Raleigh Code Camp, so any new knowledge in this area is welcome.  I'll give you the credit for alerting me and might post a copy of your SQL to illustrate another RegExp environment.
0
Pierre CorneliusCommented:
@Geert

Good point. Keeping an open mind and thinking out the box is always good when problem solving. My point was this question had nothing to do with databases or sql so in your analogy, your solution is the bullet train :)

Perhaps you should put in a request to add 'oracle database' to this questions topics so if someone is looking for that solution in future, they will find your answer, or maybe even a good idea for an article...
0
hidrauAuthor Commented:
Hello guys,

thanks for the help. Sorry for the delay. I was in another project and I had to stop to finish it first. Now I am returning to it.

Well, I keep all the sentences in access database.
0
hidrauAuthor Commented:
thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.