Solved

Advanced find and replace in text strings

Posted on 1998-12-31
30
486 Views
Last Modified: 2010-04-04

Hi experts,

I want to do an advanced "find and replace" in the following masterstring:

The masterstring is as follows

masterstring:='abc w blabla bla  abc   b bla bla bla bla abc   n bla bla  abc b bla bla bla bla abc  
w blabla bla abc   n bla bla bla bla bla bla bla';

My resultstring after find and replacing must be:

resultstring:='abc white blabla bla  abc   black bla bla bla bla abc   neutral bla bla  abc black
bla bla bla bla abc  white blabla bla abc   neutral bla bla bla bla bla bla bla';

You find several occurencies of the sub-string 'abc' in this master-string.
How can I find out, if the next non-blank after the "abc"  is a "b", "w" or "n" ?
If it is a "b", it must be replaced by "black", if the next non-blank is a "w", it must be replaced
by "white" and if the next non-blank is a "n", it must be replaced by "neutral"


There are 2 details which I know for sure about the masterstring:

a) Between "abc" and "b" (or "w" or "n") there is at least one blank.
b) The number of blanks between "abc" and "b" (or "w" or "n") is unknown.
c) There are no other characters except an unknown number of blanks
   between "abc" and "b" (or "w" or "n")    
d) The next non-blank after the "abc" will be either a "b" or a "w" or a
   "n". You won't find any other non-blanks after "abc".

Have you an idea, how this could be accomplished?

With kind regards

Mathes

P.S.:  I wish you all a happy new year.

0
Comment
Question by:mathes
  • 14
  • 10
  • 6
30 Comments
 
LVL 20

Accepted Solution

by:
Madshi earned 100 total points
ID: 1353924
Hi Mathes,

you again with another string problem...  :-)
I hope you still have my FindStr function. Otherwise say something and I'll post it again.

procedure replaceIt(var master: string);
var i1,i2 : integer;
begin
  i1:=FindStr('abc ',master,1,maxInt);
  i2:=length(master);
  while i1>0 do begin
    inc(i1,3);
    while true do begin
      if master[i1]='b' then begin
        Insert('lack',master,i1+1);
        inc(i1,5); inc(i2,4);
        break;
      end else if master[i1]='w' then begin
        Insert('hite',master,i1+1);
        inc(i1,5); inc(i2,4);
        break;
      end else if master[i1]='n' then begin
        Insert('eutral',master,i1+1);
        inc(i1,7); inc(i2,6);
        break;
      end;
      inc(i1);
      if i1>i3 then exit;
    end;
    i1:=FindStr('abc ',master,i1,maxInt);
  end;
end;

I didn't test it. But it should work...

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353925
P.S: A happy new year to you, too...  :-)
0
 

Author Comment

by:mathes
ID: 1353926
Dear Mashdi,

thank you for your answer. Yes I still have your Findstr function.
I will never remove this mighty tool from my harddisk again!!!

I tried your code.

What can I do, if the user wrote one or more characters after the "b",  or "w" or "n" ?

For example How would you handle strings like:

master:="abc ne".
master:="abc neu".

here I want the result "abc neutral" in both cases

master:="abc bl".
master:="abc blac".

here I want the result "abc black" in both cases

master:="abc wh".
master:="abc white".


here I want the result "abc white" in both cases

And finally the most complex case:

Have a look at this string:

complex_master:= "abc ne some textstuff whit some more text stuff blac  again textstuff"

Here a lazy user only once mentioned the keyword "abc". But as the coulours "black" , "white"
and "neutral are "standing alone" - delimited by one or more blanks - I know that they
belong logically to "abc". (A more detailed writing would be:
detailed_form:="abc ne some textstuff abc whit some more text stuff abc blac  again textstuff")

My desired result for complex_master is:

result_string:="abc neutral some textstuff white some more text stuff black again textstuff"

How would you do find and and replace with complex_master? Is FindStr powerful enough to master
this challenge?


With kind regards

Mathes


0
 

Author Comment

by:mathes
ID: 1353927
Hi experts,

meanwhile I found out that my problem is more complex than I realized at first sight.
This is the reason why I add this very important comment:

If the string after the abc - starting with "w" or "b" or "n" - contains a number from 1 to 8, it is NOT a colour
and must not be change to "white" or "black" or "neutral". In this case this substring must remain unchanged.

To clarify what I mean I give you 2 more examples:

master: "abc w ne4  bla text whi wh7"

the correct result is:

result:" abc white ne4 black text white wh7";

master:= "abc neu text text text bla text text text abc wh word ne word wh5 stuff abc bla morestuff";

the correct result is:

result:="abc neutral text text text black text text text abc white word neutral word wh5 stuff abc black morestuff";


As the situation is more difficult than I realized at first sight, I meanwhile increased the number of points for a correct solution.

With kind regards

Mathes
0
 

Author Comment

by:mathes
ID: 1353928
Hi experts,

meanwhile I found out that my problem is more complex than I realized at first sight.
This is the reason why I add this very important comment:

If the string after the abc - starting with "w" or "b" or "n" - contains a number from 1 to 8, it is NOT a colour
and must not be change to "white" or "black" or "neutral". In this case this substring must remain unchanged.

To clarify what I mean I give you 2 more examples:

master: "abc w ne4  bla text whi wh7"

the correct result is:

result:" abc white ne4 black text white wh7";

master:= "abc neu text text text bla text text text abc wh word ne word wh5 stuff abc bla morestuff";

the correct result is:

result:="abc neutral text text text black text text text abc white word neutral word wh5 stuff abc black morestuff";


As the situation is more difficult than I realized at first sight, I meanwhile increased the number of points for a correct solution.

With kind regards

Mathes
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353929
Hi Mathes,

what I understand is the following:
After the first " abc ", you want all " w " or " wh " or " whi " or " whit " replaced to " white ". The same with the other two colors. Right?

try this one:

procedure replaceIt(var master: string);
var i1,i2,i3 : integer;
    c1,c2,c3 : string;
begin
  c1:='black'; c2:='white'; c3:='neutral';
  master:=' '+master;  // Otherwise I wouldn't find the "abc" word
                       // if it would be right at the beginning of the master string
  try
    i1:=FindStr(' abc ',master,1,maxInt);
    i2:=length(master);
    if i1>0 then begin
      // Now we have found the magic "abc" word
      inc(i1,5);
      while true do begin
        while (i1<=i2) and (master[i1]=' ') do inc(i1);
        if i1>i2 then exit;
        i3:=i1+1;
        while (i3<=i2) and (master[i3]<>' ') do inc(i3);
        if (i3-i1<length(c1)) and CompareMem(c1[1],master[i1],i3-i1) then begin
          Insert(copy(c1,i3-i1+1,maxInt),master,i3);
          inc(i2,length(c1)-i3+i1);
        end else if (i3-i1<length(c2)) and CompareMem(c2[1],master[i1],i3-i1) then begin
          Insert(copy(c2,i3-i1+1,maxInt),master,i3);
          inc(i2,length(c2)-i3+i1);
        end else if (i3-i1<length(c3)) and CompareMem(c3[1],master[i1],i3-i1) then begin
          Insert(copy(c3,i3-i1+1,maxInt),master,i3);
          inc(i2,length(c3)-i3+i1);
        end;
        i1:=i3+1;
      end;
    end;
  finally Delete(master,1,1) end;
end;

Regards, Madshi.
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353930
well here is the algorithm... or pseudo code if you will....

FindStr('abc ',master,1,maxInt);

if master[i1] = 'b' then begin
           NextBlank := FindStr(' ', master, i1+1, Length(master));
           if NextBlank > 0 then Delete(master, i1+1, NextBlank);
           Insert('lack',master,i1+1);
           inc(i1, 5); inc(i2,4);
           break;
end...... //Do the same thing for the rest....

I have not tested this but it would be something similar to this...
if you are still having problems let us know..

btw- Madshi, would you mind sending me your FindStr() function?? 10x

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353931
Actually the line
if NextBlank > 0 then Delete(master, i1+1, NextBlank);
should probably be
if NextBlank > 0 then Delete(master, i1+1, NextBlank -1);
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353932
Viktor,

your code replaces a "brown" to a "black", too. Right? But that is not what Mathes wanted to have...

Here's my FindStr function. Much fun with it...   :-)

function FindStr(const subStr,str: string; fromPos,toPos: cardinal) : cardinal; assembler
asm      //            EAX    EDX          ECX     [ESP+8]              EAX
        TEST    EAX,EAX                  // subStr empty ?
        JE      @@noWork
        TEST    EDX,EDX                  // str empty ?
        JE      @@fail4
        TEST    ECX,ECX                  // fromPos = 0 ?
        JE      @@fail4
        PUSH    EBX
        MOV     EBX,ECX                  // EBX = fromPos
        MOV     ECX,[ESP+12]             // ECX = toPos  (+4 w/ PUSH EBX)
        TEST    ECX,ECX                  // toPos = 0 ?
        JE      @@fail3
        PUSH    ESI
        PUSH    EDI
        MOV     ESI,EAX                  // ESI = substr
        MOV     EDI,EDX                  // EDI = str
        CMP     EBX,ECX                  // fromPos > toPos ?
        JA      @@backwards
@@forwards:
        MOV     EDX,[EDI-4]              // EDX = Length(substr)
        CMP     EBX,EDX                  // fromPos > Length(str) ?
        JA      @@fail2
        CMP     ECX,EDX                  // toPos <= Length(str) ?
        JNA     @@toPosOk
        MOV     ECX,EDX                  // toPos = Length(str)
@@toPosOk:
        MOV     EDX,[ESI-4]              // EDX = Length(substr)
        DEC     EDX                      // EDX = Length(substr) - 1
        JS      @@fail2                  // EDX < 0 ?
        PUSH    EDI                      // remember str position to calculate index
        DEC     EBX                      // dec(fromPos)
        ADD     EDI,EBX                  // "Delete (str, 1, fromPos - 1)"
        SUB     ECX,EBX                  // toPos := toPos - fromPos + 1
        SUB     ECX,EDX                  // #positions in str to look at = Length(str) - Length(substr) + 1
        JBE     @@fail1                  // #positions <= 0 ?
        MOV     AL,[ESI]                 // AL = first char of substr
        INC     ESI                      // Point ESI to 2'nd char of substr
@@fwLoop:
        REPNE   SCASB
        JNE     @@fail1
        MOV     EBX,ECX                  // save outer loop counter
        PUSH    ESI                      // save outer loop substr pointer
        PUSH    EDI                      // save outer loop str pointer
        MOV     ECX,EDX
        REPE    CMPSB
        POP     EDI                      // restore outer loop str pointer
        POP     ESI                      // restore outer loop substr pointer
        JE      @@fwFound
        MOV     ECX,EBX                  // restore outer loop counter
        JMP     @@fwLoop
@@fwFound:
        POP     EDX                      // restore pointer to first char of str
        MOV     EAX,EDI                  // EDI points of char after match
        SUB     EAX,EDX                  // the difference is the correct index
        POP     EDI
        POP     ESI
        POP     EBX
        JMP     @@noWork
@@backwards:
        MOV     EDX,[EDI-4]              // EDX = Length(substr)
        CMP     ECX,EDX                  // toPos > Length(str) ?
        JA      @@fail2
        CMP     EBX,EDX                  // fromPos <= Length(str) ?
        JNA     @@fromPosOk
        MOV     EBX,EDX                  // fromPos = Length(str)
@@fromPosOk:
        MOV     EDX,[ESI-4]              // EDX = Length(substr)
        DEC     EDX                      // EDX = Length(substr) - 1
        JS      @@fail2                  // EDX < 0 ?
        MOV     EAX,EDI                  // remember str position to calculate index
        ADD     EAX,EDX                  // add backwards calculation
        SUB     EAX,2
        PUSH    EAX
        DEC     ECX                      // dec(toPos)
        ADD     EDI,ECX                  // "Delete (str, 1, toPos - 1)"
        SUB     EBX,ECX                  // fromPos := fromPos - toPos + 1
        MOV     ECX,EBX                  // swap (fromPos, lastPos)
        ADD     EDI,ECX
        DEC     EDI
        ADD     ESI,EDX
        SUB     ECX,EDX                  // #positions in str to look at = Length(str) - Length(substr) + 1
        JBE     @@fail1                  // #positions <= 0 ?
        MOV     AL,[ESI]                 // AL = first char of substr
        DEC     ESI                      // Point ESI to 2'nd char of substr
        STD
@@bwLoop:
        REPNE   SCASB
        JNE     @@fail0
        MOV     EBX,ECX                  // save outer loop counter
        PUSH    ESI                      // save outer loop substr pointer
        PUSH    EDI                      // save outer loop str pointer
        MOV     ECX,EDX
        REPE    CMPSB
        POP     EDI                      // restore outer loop str pointer
        POP     ESI                      // restore outer loop substr pointer
        JE      @@bwFound
        MOV     ECX,EBX                  // restore outer loop counter
        JMP     @@bwLoop
@@bwFound:
        POP     EDX                      // restore pointer to first char of str + backwards calculation
        MOV     EAX,EDI                  // EDI points of char after match
        SUB     EAX,EDX                  // the difference is the correct index
        CLD
        POP     EDI
        POP     ESI
        POP     EBX
        JMP     @@noWork
@@fail0:
        CLD
@@fail1:
        POP     EDX                      // get rid of saved str pointer
@@fail2:
        POP     EDI
        POP     ESI
@@fail3:
        POP     EBX
@@fail4:
        XOR     EAX,EAX
@@noWork:
end;

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353933
Viktor,

some examples for you:
  FindStr('test','blabla test blabla test blabla',1,maxInt) -> 8
  FindStr('test','blabla test blabla test blabla',9,maxInt) -> 20
  FindStr('test','blabla test blabla test blabla',maxInt,1) -> 20
  FindStr('test','blabla test blabla test blabla',19,1) -> 8

As you can see: you can even search backwards...   :-)))

Regards, Madshi.
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353934
Thanks Madshi!

I'm sure I'll have fun with it. Btw- how long did it take you to write that in assembler?? :)) Do you mind telling me a little about ASM in Delphi (protected mode)?? Just a little...

btw- Mathes, didn't mention anything about BROWN, he just said BLACK... If he uses all the colors like brown, black, orange, olive and so on then my functino won't work...you should work with Madshi's, but if all the colors that you use start with different letters then mine would work as well...

-Viktor
--Ivanov
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353935
Hi Viktor,

Mathes didn't talk about "brown". It was just an example from me. He has written:

master: "abc w ne4  bla text whi wh7"
the correct result is:
result:" abc white ne4 black text white wh7";

So he don't want to replace "ne4" to "neutral" or "wh7" to "white", what your code would do.

Hmmm. I only extended the Pos function, which is in ASM, too. Don't know anymore how much time it took. But since I'm using this function very, very often, I invested the time. Think it was about some hours...

What do you want to know about ASM? I'm no profi with that. I just tried to understand the Pos function. And finally I was able to implement my enhancements. Do you have ASM questions? Please ask them...

Regards, Madshi.
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353936
Ok, I learned ASM for DOS, but I have difficult working with ASM in Windows because of the protected mode and stuff..

ok, in DOS I could do something like this,,,

LES DI, [buffer]
where buffer is lets say an array or whatever... When I try something similar with Delphi it crashes and my program hangs...

I heard that Delphi loads all the parameters of functions in specific registers so you don't have to do that..something like this..

function Add(a, b : integer):longint; assembler;
asm
  add eax, b
end;

and this should return the sum of the two..... That's what I was trying to understand.. How does Delphi load for example A in register EAX and for exampl B in whatever register it is!?!?! That's what I was trying to learn, and I couldn't... Also would you explain some typical things about Delphi and asm that are important and are not the same as in DOS?? 10x
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353937
Ok, here is another example...

this function returns the lenght of a string in Delphi...

function Length(str : string) : Integer; assembler;
asm
  mov eax, [eax-4]
end;

Can you tell me what is actually the string in Delphi create of??

If it's zero based you could do something like this...

function StrLen(str : string) : Integer; assembler;
asm
  les di, [str]
@@Looper:
  cmp es:[di], 0
  je Done
  inc di
loop Looper
@@Done:
end;

and so on.... and maybe do mov @result, ecx

and so on.. Can you tell me how this can be done in Delphi??

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353938
Ok, here is an example for one of the things I was talking about.... How do you know for each of these where it gets loaded???

function FindStr(const subStr,str: string; fromPos,toPos: cardinal) : cardinal; assembler;
asm                //           EAX    EDX           ECX       [ESP+8]                 EAX

And what is [ESP+12] in the case with your FindStr() function??

I hope you can answer my silly questions...
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 20

Expert Comment

by:Madshi
ID: 1353939
Ok, how the parameters are given into a function depends on the calling convention. Pascal convention does it in another way then cdecl does it or stdcall does it.
The standard Delphi convention works in this way:
The first 4-byte parameter is stored in EAX (32 bit AX register). The second one in EDX, the third one in ECX. The other parameters are put on the stack [ESP+8], [ESP+12], [ESP+16], ...
The result value must be put to EAX.
The [ESP+12] in my FindStr function is originally [ESP+8], but since there is a "push" command before the line with the [ESP+X], the parameter moves from [ESP+8] to [ESP+12].
I don't know how this "les" command worked in dos. I think it was this way because of the segment/offset stuff.

Perhaps you should try to understand the FindStr sources and ask me if you have any problems with that.

function Add(a, b : integer):longint; assembler;
asm
  add eax, b
end;

Does this function work this way? I don't know. I would have written:
  add eax,edx

After reading what I've written above about the parameters and the registers you should understand why I would do it this way. But probably Delphi is that clever that you can directly use "b" instead of "edx". Don't know that.

function Length(str : string) : Integer; assembler;
asm
  mov eax, [eax-4]
end;

You know now that the "str" parameter is stored in EAX. So the line
  mov eax, [eax-4]
simply moves the integer value that is stored IN FRONT OF the first string character to the EAX register (that is the result register, you remember).
You're not completely right with what you're saying about Delphi strings...
In C(++) you have pchar. You must allocate/deallocate it yourself and the length depends only on the terminating 0 character.
Do you know the old 255-byte Delphi strings? In the first byte (str[0]) the length of the string was saved.
The new long Delphi strings are somehow a mixture of both systems.

type StrRec = record
                allocSiz: Longint;
                refCnt:   Longint;
                length:   Longint;
              end;

If you look into the system.pas unit, you'll find this StrRec type. This 12 bytes are stored in front of the first character of each and every Delphi string. That means: An empty string consumes 12 bytes!
You see here, Delphi stores the allocated size of the string, the current length of the string and the reference count.
So if you shorten a Delphi string, Delphi perhaps does NOT reallocate it, but only changes the length integer. And if you ask "length(str)" Delphi does NOT look for a 0 character, but only gives you the integer.
Do you now understand how the assembler function "length" works? The integer in front of the first string character is the length integer. Everything clear now?
Now this Delphi string mechanism has multiple advantages:
(1) You can put "wild" data into a Delphi string. Nobody has a problem even with 0 characters, as long as you don't convert it to a pchar type.
(2) Delphi has a quite intelligent mechanism if you copy strings. Delphi does NOT copy the characters, but only creates a new 12 byte record, increments the reference count and that was it. But in the moment where you change the first character of one of the both strings, the characters are automatically copied. That's nice, isn't it?
So Delphi strings are often much faster then using pchar.

Some more infos:
Sometimes you want ask not the "length integer", but the "0 character length" of a Delphi string. These two values are different, if there are 0 characters in the middle of the string. So you can write:
  delphiStr:=pchar(delphiStr);
This conversion shortens automatically the delphi string after the first 0 character.
If you want to get the address of the first character you can either write "@str[1]" or "pointer(str)" or "pchar(str)". All the same.
BTW, the same mechanism is implemented for wideString!!! And - what is very nice - you can let Delphi convert a string to a wideString simply by writing:
  wStr:=str;
The characters are automatically converted by Delphi!!!

Any more questions about strings?

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353940
Ufff. That was hard work...   :-)

I haven't done much assembler programming in dos. So I can't tell you much about the differences between dos assembler and win32/Delphi assembler...
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353941
Hey, that was a perfect explanation... You can be a good teacher u know :))

ok, I have a few more questions about the strings... I understood the parameters stuff in assembler....

in the ADD() function it works if you do this also...

function add(a, b : integer):integer;
begin
  asm
    add a, b
    mov @result, a
  end
end;

It works also, and thank god Delphi is so smart :)

Ok, I really thank you for telling me how the functin thing works!!

eax, edx, ecx, [esp+4], [esp+8] ok got 'em already :)

Do the procedures work the same way??

procedure whatever(a, b : integer); assembler
asm
.......
end;

Ok, what about if the parameter is VAR NameOfParam.....which means it will pass the address.... What about if you want to work with it in assembler??

ok, if I want to get the value from the address in A and return it as the result of the function is this the way to do it??

function GetValue(var A : Integer) : Integer; assembler;
asm
  mov eax, [eax]
 //What about if you do MOV EAX, EAX ??? Is it gonna return the pointer to var A???
end;

Is this the way to do it? I'm really curious about that....

You asked about LES... les simply loads the address of a variable or whatever....

LES DI, BUF is the same as the following code,,,
.........
mov ax, seg buf
mov es, ax
mov di, offset buf
........

then es:di points to BUF
.Yeah, les is used for the segment : offset way of memory mapping... Ok, so in protected mode (Windows for example) the memory is said to be flat right?? What does that mean?? It's no seg:ofs so what is it??

About strings.... I still don't understand how the strings in Delphi work!!!

Ok, string[0] should be the location of the LENGHT of the string...but delphi doesn't allow that so you can do it with assembler by doing mov eax, [eax-4] because integer is 4 bytes... OK, I don't understand how does the delphi compiler (or memory manager) knows which records belongss to which string that you create...

ok, lets say you careate a variable

var STR : string;

how does the compiler associates the record to the STR variable??

oh i read your comment again and i think i understood it this time... It saves the record at in front of the string which is something like STR[0] but is 12 bytes right??? but the compiler doesn't allow you to actually get this info just like STR[0]... ok, so when you do mov eax, [eax-4] doesn't it move the value of allocSiz to the EAX register instead of lengh variable from the record of that string??

 allocSiz: Longint;  [EAX-4]
 refCnt:   Longint;   [EAX-8]
 length:   Longint;   [EAX-12]

isn't that the way you acces them??? I'm just confused about that!! WOuld you explain it please?? 10x for all the help.

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353942
opppps.....
eax, edx, ecx, [esp+4], [esp+8] ok got 'em already :)
this was wrong wasn't it...
eax, edx, ecx, [esp+8], [esp+12] now i really got it :))
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353943
Hi Viktor,

>> Hey, that was a perfect explanation... You can be a good
>> teacher u know :))
Thanx... :-)
It seems that you did understand almost everything of what I've written. So you seem to be a good pupil, too...   :-)

>> function add(a, b : integer):integer;
>> begin
>>   asm
>>     add a, b
>>     mov @result, a
>>   end
>> end;
>> It works also, and thank god Delphi is so smart :)
Yes, thanks be to God!

>>Do the procedures work the same way??
Hmm. I'm quite sure it'll be this way, too (though I didn't test it). Only difference is probably that the EAX value is NOT returned.

>> Ok, what about if the parameter is VAR NameOfParam.....which
>> means it will pass the address.... What about if you want to
>> work with it in assembler??
>> ok, if I want to get the value from the address in A and
>> return it as the result of the function is this the way to do
>> it??
>> function GetValue(var A : Integer) : Integer; assembler;
>> asm
>>   mov eax, [eax]
>>  //What about if you do MOV EAX, EAX ??? Is it gonna return
>>      the pointer to var A???
>> end;
>> Is this the way to do it? I'm really curious about that....
Again I'm quite sure that it is exactly the way you think that it is - though I didn't test that, either. But it MUST be this way - otherwise it would not be logical... I would bet that you're right with that.

>> You asked about LES... les simply loads the address of a
>> variable or whatever....
>> LES DI, BUF is the same as the following code,,,
>> .........
>> mov ax, seg buf
>> mov es, ax
>> mov di, offset buf
>> ........
>> then es:di points to BUF
>> .Yeah, les is used for the segment : offset way of memory
>> mapping... Ok, so in protected mode (Windows for example) the
>> memory is said to be flat right?? What does that mean?? It's
>> no seg:ofs so what is it??
You're right. This is all segment/offset stuff and is thus invalid in win32 assembler. If you want to access the content of a pointer you just write [pointer], like you did with [EAX] or [EAX-4]. It's much easier, isn't it?
Ok, something about flat memory:
Flat memory means that you don't have two words (segment/offset) that are combined somehow to get the real address, but that you have just a dword value, that can simply go from $0 to $FFFFFFFF. That means you can access with one pointer 4 GB memory. That's quite mighty, isn't it?
Now in win32 it is even better: Each and every process has it's own 4 GB memory "context". That means that every process can theoretically use real 4 GB RAM. If process A accesses address $01234567, win32 (the CPU supports this kind of virtual memory mapping) maps this pointer to either a position in RAM or a position in the swap file or ...
If process B accesses the same address, win32 maps this pointer to a position that is different from the one from process A.
That means if you write two programs, and one of the program gives a pointer to a data block to the other process, then the pointer will be invalid in the other process. You just can't access data that is in the memory/address context of another process. That's real system security!!!
Then win32/CPU have some memory blocks that are protected. So if you try to access them, you'll get an access violation. E.g. the addresses from $0 to $FFF are protected to detect nil pointer problems. Note, that nothing happens if you're trying to write to a nil pointer. The only thing that happens is that the CPU fires an access violation. Of course memory blocks that are not allocated yet would produce an access violation, too - if you would try to access them.
Uff, quite complex... But quite intelligent!
If you want to know all about these basic concepts you should look at the book "Advanced Windows" by Jeffrey Richter.

>> About strings.... I still don't understand how the strings in
>> Delphi work!!!
>> Ok, string[0] should be the location of the LENGHT of the
>> string...but delphi doesn't allow that so you can do it with
>> assembler by doing mov eax, [eax-4] because integer is 4
>> bytes... OK, I don't understand how does the delphi compiler
>> (or memory manager) knows which records belongss to which
>> string that you create...
>> ok, lets say you careate a variable
>> var STR : string;
>> how does the compiler associates the record to the STR
>> variable??
>> oh i read your comment again and i think i understood it this
>> time... It saves the record at in front of the string which
>> is something like STR[0] but is 12 bytes right??? but the
>> compiler doesn't allow you to actually get this info just
>> like STR[0]...
Yes, you got it!

>> ok, so when you do mov eax, [eax-4] doesn't it
>> move the value of allocSiz to the EAX register instead of
>> lengh variable from the record of that string??
>> allocSiz: Longint;   [EAX-4]
>> refCnt:   Longint;   [EAX-8]
>> length:   Longint;   [EAX-12]
>> isn't that the way you acces them??? I'm just confused about >> that!! WOuld you explain it please?? 10x for all the help.
Nope, if you would extend the record with the string data, it would look like this:
type StrRec = record
                allocSiz: Longint;                      [EAX-12]
                refCnt:   Longint;                      [EAX- 8]
                length:   Longint;                      [EAX- 4]
                chars:    array [0..XXXXXXX] of char;   [EAX- 0]
              end;
Now you should see that if you use [EAX-4], you really get the length of the string.
BTW, Borland decided to deny access to str[0], because so everyone had to look at his string functions again and do the nessecary conversion. Of course Borland could have handle str[0] like a property which at read access just calls "GetLength" and at write access "SetLength", but that would have been not so clean...
BTW, do you have Delphi4? The dynamical arrays (I LOVE THEM!!!!!!!!!!!!) work almost the same way as the strings does! You can call SetLength/GetLength there, too.

More questions?

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353944
Hmm, hi Mathes, sorry for misusing your question...   :-)
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353945
Well, I got Delphi4. but I haven't had much time the last couple of months to use Delphi that much. I go to school, and all the homework that I gotta do  (well I don't do most of it :), and I come back from school at 4 a clock and I just don't have time to learn all the stuff I want. I'm in a school break at the moment and on monday I'm going back to school again. Now that had a two weeks break off school I was trying to learn new stuff.... I learned about grpahics programming in DOS, C/C++, assembler, and a lot more... I really liked that you explained to me how all the strings stuff works, because I wasn't sure how it actually works. Well, when you think that I've been using a computer for only one year till now, and I've been programming for only 5-6 months or so, i think I've learned quite a lot for the time I've been programmig :)
I started off with Windows, and now I'm working in DOS (primiraly games anf graphics) which I really love doing. I have not done any database programming yet and no internet programming... Other than that, I think I've tried almost everything else.. Oh, I also gotta learn VC++, because I want to know it also... I see that there are not that many jobs for Delphi programmers as there are for C programmers even though I ebjoy working with Delphi a lot more than I do with C/C++.

Ok, anyway, I think that you've given me a SUPER lesson, so for now I don't have any questions... If I get some questions on my mind I'll ask, since i see you know quite a lot about programming and all that... YOu might be a teacher of mine in a few years when I gradute from high school :)) If you become a teacher let me know... I'll be in your class... I'll also loook for your name in the newspapers for being the next Bill Gates. YOu might create a new OS called Doors 98 instead of Windows 98 ;-)

Anyway, I really appreciate the time you took to answer my silly questions. I also sorry about misusing mathes space  :(

I'll post a dummy question so you can get some points for sharing your knowledge with me :)

Thanks a lot!

If I have other questions about something I'll let you know, ok? :)

-Viktor
--Ivanov
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353946
Hi Viktor,

I understand when you're saying that you've not so much time... I'm working 4 days the week, the rest of the week I'm studying economics in the same speed as fulltime students do...
However: My job is Delphi programming and - I love it!   :-)

>> I started off with Windows, and now I'm working in DOS
>> (primiraly games anf graphics) which I really love doing.
I've done some dos game programming with TP6. But I like Delphi much more. At the end of my dos time, I've written most of my units for both TP6 and Delphi, so I was able to work in Delphi.
Hmm. I think, if you want to write games today, you'll have to leave dos and use DirectX, don't you think so?
And since COM is much better implemented in Delphi then in C(++), we can use Delphi for that...  :-)))

>> I have not done any database programming yet and no internet
>> programming...
The same with me...

>> Oh, I also gotta learn VC++, because I want to know it also...
>> I see that there are not that many jobs for Delphi
>> programmers as there are for C programmers even though I
>> ebjoy working with Delphi a lot more than I do with C/C++.
You're right with that. I hope I'll have my own firm some day, then I can decide which language to use. However I'm a little bit frightened about Linux and BeOS and blabla. I would really like to look at these systems - but there is no DELPHI for these languages...   :-((((((((
Hmmm. Yet?

>> If I get some questions on my mind I'll ask, since i see you
>> know quite a lot about programming and all that...
Thanx for this compliment!  :-)))
I think in some things (like strings and memory context) I know quite a lot about programming - in other things (e.g. databases) I know almost nothing... But programming is my job (thanx God for that!). So I can learn a lot at my job...

>> YOu might be a teacher of mine in a few years when I gradute
>> from high school :)) If you become a teacher let me know...
>> I'll be in your class...
Hmmm. There are a lot of things that I could do. But I don't think I'll become a teacher. I think I would like to teach, but only sometimes. Most time I prefer writing my own programs...

>> I'll also loook for your name in the newspapers for being the
>> next Bill Gates. YOu might create a new OS called Doors 98
>> instead of Windows 98 ;-)
Hmm. I would love that. But it's a long way...  :-)))
But I see you're quite optimistic, so am I!!!

>> I'll post a dummy question so you can get some points for
>> sharing your knowledge with me :)
You don't need that. Though... Some points, and I'll (finally) enter the hiscore list...  :-)))

>> If I have other questions about something I'll let you know, ok? :)
I surely will - thanx...  :-)

Regards, Madshi.
0
 

Author Comment

by:mathes
ID: 1353947
Dear Madshi,

thank you for your source code. I am happy that you understood quite well what I want to achieve,
although it was not easy for me to explain the tricky structure of my masterstrings.
There are indeed only the colours "white" ,"black" and "neutral" to be handled, so I needn't to
worry about other colours like olive, red, blue...
And you are right to assume that  "you want all " w " or " wh " or " whi " or " whit " replaced
to " white ". The same with the other two colors. Right?" This is exactly what I need.

However you assume something which I do not want: "

"After the FIRST " abc ",

The replacement must not be limited to only the first occurence of "abc".
If you find "abc" several times in my master string, the following colours should be changed in the same way as
if they occured after the first occurrence of "abc".

so a masterstring master:="abc whi re4 bf5 pa7b7c7 abc b qf8 rh6 abc neu5"

should be changed to: result:="abc white re4 bf5 pa7b7c7 abc black qf8 rh6 abc neu5"

(As you alrady know: "neu5" must NOT be changed to "neutral5, because "neu5" contains a number from 1 to 8,
a "5" in this case. BTWQ: The numbers from 1 to 8 help me to distinguish between colours and normal text.)


I don't know if your routine changes really all colours, even after the second,third, fourth... occurence of
"abc"

When I tried to compile your source, Delphi 3.0 showed me an error message:


in the line:


if (i3-i1<length(c1)) and CompareMem(c1[1],master[i1],i3-i1) then


Delphi complains about:


"incompatible types 'char' and 'pointer'.


Can you please tell me what is wrong here ? I would be very very happy, if you provided me with a bug-free
routine that can handle all types of masterstrings which I explained to you.


With kind regards

Mathes

P.S.: I don't mind your talking about assembler, but please don't be angry, if I don't make comments
about assembler. I have no knowledge about assembler at all.
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1353948
Mathes where it shows you the error just add the @ symbol so you can pass the pointer of that string isntead of the character and everything should work fine...
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353949
Yes Viktor is right. It seems that CompareMem's paramter type has changed from Delphi3 to Delphi4.
The strange thing is: In Delphi4's help file they say I'll have to use "@buf", but in Delphi4 won't accept that. So I deleted the "@" in my sources...

Regards, Madshi.

P.S: Yes, this function should do exactly what you wanted.
Only one question:
"abc bxx b1"
You said you don't want "b1" to be replaced with "black", since there's a number in "b1". Do you want to have "bxx" be replaced with "black"??? My code does neither replace "bxx" nor "b1", but "b", "bl", "bla", and "blac" to "black". The same with the other two colors. Is that right?

Regards, Madshi.
0
 

Author Comment

by:mathes
ID: 1353950
Dear Madshi,

I am happy to hear that the code will handle all occurrencies of "abc" and not only the
first one. It is perfectly right that you don't change all bxx to black. I want to find
and replace only the colour black,white and neutral. So if you find for example after the
"b" another character than "l", it is clear that it can't be the colour "black" and as a
consequence of this it must not be changed.

I meanwhile did some editing with the procedure and added some "@" where Delphi asked for
an error correction:

procedure TrimColour(var master: string);
var
  i1, i2, i3: integer;
  c1, c2, c3: string;
begin
  c1 := 'black'; c2 := 'white'; c3 := 'neutral';
  master := ' ' + master; // Otherwise I wouldn't find the "abc" word
                            // if it would be right at the beginning of the master string
  try
    i1 := FindStr(' abc ', master, 1, maxInt);
    i2 := length(master);
    if i1 > 0 then begin
           // Now we have found the magic "abc" word
      inc(i1, 5);
      while true do begin
        while (i1 <= i2) and (master[i1] = ' ') do inc(i1);
        if i1 > i2 then exit;
        i3 := i1 + 1;
        while (i3 <= i2) and (master[i3] <> ' ') do inc(i3);
        if (i3 - i1 < length(c1)) and CompareMem(@c1[1], @master[i1], i3 - i1) then
        begin
          Insert(copy(c1, i3 - i1 + 1, maxInt), master, i3);
          inc(i2, length(c1) - i3 + i1);
        end else if (i3 - i1 < length(c2)) and CompareMem(@c2[1], @master[i1], i3 - i1)
          then begin
          Insert(copy(c2, i3 - i1 + 1, maxInt), master, i3);
          inc(i2, length(c2) - i3 + i1);
        end else if (i3 - i1 < length(c3)) and CompareMem(@c3[1], @master[i1], i3 - i1)
          then begin
          Insert(copy(c3, i3 - i1 + 1, maxInt), master, i3);
          inc(i2, length(c3) - i3 + i1);
        end;
        i1 := i3 + 1;
      end;
    end;
  finally Delete(master, 1, 1) end;
  end;

Then I tested the routine TrimColour in a code similar to this:

 for i := 0 to stringlist.count - 1 do
   begin
    edit1.text := TrimColour(stringlist.strings[i]);
   end;

But unfortunately, Delphi refuses to compile this.
Delphi says: "a constant can't be used as a var-parameter".

But I urgently need the changed string in the text field of an entry form.

How can I use the TrimColour routine in my test program?

With kind regards

Mathes


0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353951
The problem is that stringlist.strings[XX] is a property and you can't use properties as a var parameter.

So you have to do this:

for i := 0 to stringlist.count - 1 do
   begin
     s1:=stringlist.strings[i];
     TrimColour(s1);
     edit1.text:=edit1.text+s1;
   end;

Regards, Madshi.
0
 

Author Comment

by:mathes
ID: 1353952
Dear Mashdi,

Your code which you sent me works really very well and I want to thank you for your excellent work.
You really deserved the points. Moreover you are indeed not only a great coder, you are an instructive teacher as well!

Thank you !!!!!!!!!!

With kind regards

Mathes
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353953
Wow - thank you for such big compliments...  :-)))
And - thank you for bringing me the first time to the top15!  :-)))

Regards, Madshi.

Ahem - I really can live with it that you call me "Mashdi" every second time - originally my name is "Madshi", not "Mashdi". But it doesn't matter. Perhaps it's easier for you to remember that I am simply "Mad" plus something...   :-)
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now