Posted: Tue Feb 01, 2005 10:12 pm
Oh, I didn't know that you can directly read one byte with \b ... is this documented?
Code: Select all
Procedure MidSet_Fast(*PtrStr.BYTE, DestPos.l, DestLen.l, *ReplaceStr.BYTE)
If DestLen>1
*PtrStr+DestPos-1+DestLen
LastChar.b=*PtrStr\b
PokeS(*PtrStr-DestLen, PeekS(*ReplaceStr, DestLen))
*PtrStr\b=LastChar
Else
*PtrStr+DestPos-1
*PtrStr\b=*ReplaceStr\b
EndIf
EndProcedure
Code: Select all
Procedure MidSet_Fast(*PtrStr.BYTE, DestPos.l, DestLen.l, *ReplaceStr.BYTE)
If DestLen>4
CopyMemory(*ReplaceStr,*PtrStr+DestPos-1,DestLen)
ElseIf DestLen=1
*PtrStr+DestPos-1
*PtrStr\b=*ReplaceStr\b
ElseIf DestLen=2
*PtrStr+DestPos-1
*PtrStr\b=*ReplaceStr\b
*PtrStr+1
*ReplaceStr+1
*PtrStr\b=*ReplaceStr\b
ElseIf DestLen=3
*PtrStr+DestPos-1
*PtrStr\b=*ReplaceStr\b
*PtrStr+1
*ReplaceStr+1
*PtrStr\b=*ReplaceStr\b
*PtrStr+1
*ReplaceStr+1
*PtrStr\b=*ReplaceStr\b
ElseIf DestLen=4
*PtrStr+DestPos-1
*PtrStr\b=*ReplaceStr\b
*PtrStr+1
*ReplaceStr+1
*PtrStr\b=*ReplaceStr\b
*PtrStr+1
*ReplaceStr+1
*PtrStr\b=*ReplaceStr\b
*PtrStr+1
*ReplaceStr+1
*PtrStr\b=*ReplaceStr\b
EndIf
EndProcedure
Code: Select all
Procedure.s SetMid(old.s, start.l, length.l, new.s)
Protected count.l
count = Len(old)
If start < 1 Or start > count
ProcedureReturn old
EndIf
count = (count - start) + 1
If length < 0 Or length > count
length = count
EndIf
ProcedureReturn Left(old, start - 1) + new + Mid(old, start + length)
EndProcedure
Code: Select all
s = SetMid("male", 3, 0, "p") ; returns "maple"
s = SetMid(s, 1, 1, "") ;returns "aple"
s = SetMid(s, 3, 0, "p") ; returns "apple"
Code: Select all
Procedure$ SimpleXOR (pNStr$)
Protected sLen = Len(pNStr$)
Protected sEn.w, tXr.c = 64
For sEn = 1 To sLen
PokeC(@pNStr$ + (sEn - 1) * SizeOf(tXr), Asc(Mid(pNStr$, sEn, 1)) ! tXr) ; a kind of Mid$ =
Next
ProcedureReturn pNStr$
EndProcedure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Define.s A = SimpleXOR("test")
Define.s B = SimpleXOR(A)
Debug A
Debug B
Code: Select all
Structure _CMidStruct
c.c[0]
EndStructure
Threaded *_CMid._CMidStruct
Macro CRep(StringVar, Position, NewChar)
*_CMid = @StringVar
*_CMid\c[(Position)-1] = (NewChar)
EndMacro
test$ = "Hello World!"
Debug test$
CRep(test$, 1, 'W')
CRep(test$, 7, 'H')
CRep(test$, 12, '?')
Debug test$
Code: Select all
Macro CRep(StringVar, Position, NewChar)
PokeC(@StringVar + ((Position)-1)*SizeOf(CHARACTER), Asc(NewChar))
EndMacro
test$ = "Hello World!"
Debug test$
CRep(test$, 1, "W")
CRep(test$, 7, "H")
CRep(test$, 12, "?")
Debug test$
Code: Select all
; that first one can only "mid" single char of string
; problems will be if Pos set incorrectly
Macro PoorMidEmulation (pStr, Pos, Char)
CompilerIf #PB_Compiler_Unicode
PokeC(@pStr + (Pos - 1) * 2, Asc(Char))
CompilerElse
PokeC(@pStr + (Pos - 1), Asc(Char))
CompilerEndIf
EndMacro
; that second is a bit improved, it can "mid" a whole part of string
; again, problems will be if Pos set incorrectly
Macro PoorMidEmulation2 (pStr, Pos, Char)
CompilerIf #PB_Compiler_Unicode
CopyMemory(@Char, @pStr + (Pos - 1) * 2, Len(Char) * 2)
CompilerElse
CopyMemory(@Char, @pStr + (Pos - 1), Len(Char))
CompilerEndIf
EndMacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Define.s TEST = "test"
Debug TEST ; clear variable
PoorMidEmulation(TEST, 1, "R")
Debug TEST ; mid = single char
PoorMidEmulation2(TEST, 2, "ock")
Debug TEST ; mid = part of string
Code: Select all
Macro SRep(StringVar, Position, NewString, MaxChars = -1)
PokeS(@StringVar + ((Position)-1)*SizeOf(CHARACTER), (NewString), MaxChars, #PB_String_NoZero)
EndMacro
test$ = "Hello World!"
Debug test$
SRep(test$, 2, "ond")
SRep(test$, 8, "eir???", 3)
Debug test$
No, because InsertString does what it says: it only inserts. AFAIK, PB does not have a procedure to insert/replace parts of a string using only position and length as the MID$ statement does in other BASIC dialects.Dude wrote:Doesn't InsertString() do what you want?
http://www.purebasic.com/documentation/ ... tring.html
It is not more ilogical than "swap" keyword for example.Frarth wrote:@Lunasole, I would not try to hold on to the 'beauty' of the MID$ = syntax, simply because you were used to it. In the BASIC world that statement was inconsistent, illogical and to some even confusing. The syntax is a left-over from the days when programming languages only had to deal with 1-byte characters (ASCII). Today we have multi-byte character encodings which makes things more complicated and comparatively slower because of the memory overflow checking and string space adjustment, which is inevitable.
I didn't said about your example (and other previous here used procedure return), just noticed that this is different from what Mid = meant to do. Surely your solution is fine as it works.Frarth wrote: The easiest and best solution may not be the 'fastest' but unless you need to manipulate thousands of strings in a row, my example works great and is even more flexible allowing to insert strings as well, which I use quite often. Also, these days computers are so much faster than in the 1-byte days, that my example processes faster than MID$ on the early computers.
Code: Select all
T$ = "test"
ReplaceString(T$, "e", "o", #PB_String_NoCase | #PB_String_InPlace, 2, 1)
;comparing to mid macro:
MidS(T$, 2, "o")
When I say illogical and confusing, I mean that the three basic functions LEFT$, RIGHT$ and MID$ behave the same. If MID$= is allowed, then LEFT$= and RIGHT$= should also be allowed? This is what I find illogical. But that is just my personal opinion.Lunasole wrote:It is not more ilogical than "swap" keyword for example.
Sorry, I thought the request to insert something with Mid, but I see now the request is to replace a character (or characters) in-place, at the specified position. My bad.Frarth wrote:InsertString does what it says: it only inserts.
Come now, is using Left and Right so bad?eevee wrote:I now have to use something as convoluted as
So make it a macro instead, which doesn't suffer the overheads of procedures.eevee wrote:set it as a Procedure (with the parameter-passing overheads that would incur)