Page 1 of 2

Inserting text in strings

Posted: Tue Oct 05, 2004 11:42 pm
by ukandrewc
Hello

I am just wondering how to insert a string into a string in PB.

I tried using

Code: Select all

Mid(MyString,1,5)="hello"
But that causes a compiler error

Thanks

Posted: Wed Oct 06, 2004 4:26 am
by sec

Code: Select all

Procedure.s instr(mstr.s, strinsert.s, pos.l)
  ProcedureReturn Mid(mstr, 1, pos-1) + strinsert + Mid(mstr, pos, Len(mstr)-pos+1)
EndProcedure

a.s = "hello"
b.s = "123"

Debug instr(a, b, 2) ; h123ello

Posted: Wed Oct 06, 2004 8:21 am
by blueznl
or the old classical:

i$ = "123"
x$ = "abcdef"
x$ = Left(x$,3)+i$+Mid(x$,4,63999)
Debug x$

note that mid$() in pure does not allow some variations possible in other basics:

x$ = mid$(x$,5)="12345"
... would be insert 12345 at position 5 in string x$ (so the '1' would be the 5th character)

x$ = mid$(x$,5,3)="12345"
... would replace character 3 characters with 12345 (thus making x$ longer)

Posted: Wed Oct 06, 2004 12:01 pm
by ukandrewc
Thanks all

That's a shame because those methods all require the creation of temporary strings.

In other Basics, mid is faster becuase it just inserts into existing string space. As I am trying to rearrange 400k string, it will add time.

Thank you

Posted: Wed Oct 06, 2004 2:19 pm
by GedB
Here's a ReplaceStringAt procedure that uses pointer manipulation.

You could optimise it further by using Assembler.

Code: Select all

Enumeration ;ReplaceStringAt results
  #ReplaceStringAt_OK
  #ReplaceStringAt_PositionGreaterThanDestinationLength
  #ReplaceStringAt_PositionPlusLengthGreaterThanDestinationLength
  #ReplaceStringAt_LengthGreaterThanReplacementLength
EndEnumeration

Procedure ReplaceStringAt(*Pd, *Pr, Position, Length)
  ;Loop through the string to the requested position, ensuring we don't reach the end
  ;of the destination string
  For i = 1 To Position - 1
    If PeekB(*Pd) = 0
      ProcedureReturn #ReplaceStringAt_PositionGreaterThanDestinationLength
    EndIf
    *Pd + 1
  Next i
  
  For i = 1 To Length
    ;as we move through both the source and destination ensure that 
    ;we don't reach the end of either
    If PeekB(*Pd) = 0
      ProcedureReturn #ReplaceStringAt_PositionPlusLengthGreaterThanDestinationLength
    EndIf
    If PeekB(*Pr) = 0
      ProcedureReturn #ReplaceStringAt_LengthGreaterThanReplacementLength
    EndIf
    PokeB(*Pd, PeekB(*Pr))
    *Pd + 1
    *Pr + 1
  Next i  
EndProcedure

Procedure assert(Test, Description.s)
  If Test 
    Debug Description + ": Pass"
  Else
    Debug Description + ": Fail"
  EndIf
EndProcedure


;Test a good request
t.s = "123456789"
Result = ReplaceStringAt(@t, @"XXX", 4, 3)
assert(Result = #ReplaceStringAt_OK And t = "123XXX789", "OK")

;If the replacement is shorter than length it is ignored
t.s = "123456789"
Result = ReplaceStringAt(@t, @"XXXXX", 4, 3)
assert(Result = #ReplaceStringAt_OK And t = "123XXX789", "OK")

;If the position is off the end of the destination the string
;will remain unchanged.
t = "123456789"
Result = ReplaceStringAt(@t, @"XXX", 11, 3)
assert(Result = #ReplaceStringAt_PositionGreaterThanDestinationLength And t = "123456789", "PositionGreaterThanDestinationLength")

;If the replacment runs off the end of the destinatino we
;change what we can but destination is not extended.
t = "123456789"
Result = ReplaceStringAt(@t, @"XXX", 8, 3)
assert(Result = #ReplaceStringAt_PositionPlusLengthGreaterThanDestinationLength And t = "1234567XX", "PositionPlusLengthGreaterThanDestinationLength")

;If replacement is shorter than the given length we replace what we have
t = "123456789"
Result = ReplaceStringAt(@t, @"XXX", 4, 5)
assert(Result = #ReplaceStringAt_LengthGreaterThanReplacementLength And t = "123XXX789", "LengthGreaterThanReplacementLength")

Posted: Wed Oct 06, 2004 2:53 pm
by blueznl
ucandrewc, you didn't read my sample properly :-)

anyway, 400k doesn't fit in a pb string, so that example is irrelevant :-)

Posted: Wed Oct 06, 2004 5:45 pm
by ukandrewc
Hello All

Thanks GedB, I forgot that you can use pointers in PB. I only use it occasionally to create DLL's when VB can't cope.

blueznl: I may wrong but the line:

Code: Select all

x$ = Left(x$,3)+i$+Mid(x$,4,63999)
would create a working string before assigning it to x$ ??

Also, I have passed a 400K string to PB from VB, and am able alter and pass it back. Is this not supposed to happen?

Posted: Wed Oct 06, 2004 6:21 pm
by wilbert
ukandrewc wrote:Also, I have passed a 400K string to PB from VB, and am able alter and pass it back. Is this not supposed to happen?
When you use a PB function that returns a string, the function stores the result in a buffer and the application retrieves that string from the buffer and assigns it to the variable the result should be assigned to.

The standard buffer size is 64000 bytes. If you manipulate a string yourself, without using this buffer, a 400KB string is no problem at all. If you do want to use such a string with the PB functions, you have to increase the buffer size. For testing purposes I worked with a 4 megabyte string that way without any problems.

Posted: Wed Oct 06, 2004 7:29 pm
by ukandrewc
Thanks for the info wilbert.

I assume that you mean the working buffer space? If so how do you increase it?

I have used the following:

Code: Select all

ProcedureDLL.l SortString(Str.s)
x$=mid(Str,300000,10)
debug x$
Which is fine for my needs as I am only need to find strings of <100 characters.

Posted: Wed Oct 06, 2004 9:52 pm
by blueznl
300000? can't be, should be max 63999

Posted: Wed Oct 06, 2004 11:29 pm
by ukandrewc
This is the VB code

Code: Select all

test = Space$(100010)
Mid$(test, 100000, 10) = "hello mum!"
TestString test
This is the PB code:

Code: Select all

ProcedureDLL TestString(Test.s)
MessageRequester(Str(Len(Test)),Mid(Test,100000,10))
EndProcedure
It works - but if you say it can't, then I will use it but pretend that it doesn't :roll:

Andrew

Oh, my aching sides

Posted: Thu Oct 07, 2004 1:14 am
by Fangbeast
ukandrewc wrote: It works - but if you say it can't, then I will use it but pretend that it doesn't :roll:

Andrew
Thanks, I just fell off the chair laughing and hurt myself:)

Posted: Thu Oct 07, 2004 2:15 am
by Dare2
hehe.

There is a thread here somewhere where large strings were discussed. (I can't find the thread now so maybe it was in th bugs area and dopped or maybe I am searching badly - but I remember seeing it)

From recollection (vague) the conclusion was that very large strings give the illusion of being OK, but cause probs down the track. There was also some sort of work-around which was hotly argued.

Posted: Thu Oct 07, 2004 4:47 am
by wilbert

Code: Select all

; free the old string buffer

! pushd [_PB_StringBase]
! pushd 0
! pushd [_PB_MemoryBase]
! call _HeapFree@12

; allocate a new string buffer of 512KB

! pushd 524288
! pushd 8
! pushd [_PB_MemoryBase]
! call _HeapAlloc@12
! mov [_PB_StringBase],eax

; create a 400KB string

myLongString.s = Space(409600)

Debug Len(myLongString)
This works fine for me.
What could cause problems is if there are string functions with a loop inside that is based on a 16 bit counter (for example in asm cx instead of ecx) but I don't know if there are PB functions like that.

Posted: Thu Oct 07, 2004 9:29 am
by ukandrewc
Thanks wilbert, that is a great help.

I mainly use PB for creating faster routines to call from VB.

I hadn't realised about the string limit - probably because I tend to pass strings from VB.