Private Declare Sub CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" _
(pDst As Any, _
pSrc As Any, _
ByVal ByteLen As Long)
Sub ReplaceAt(lStringPtr As Long, _
lReplacePtr As Long, _
lReplacePos As Long, _
lReplaceLenB As Long)
'lStringPtr will the StrPtr of the string to do the replace in
'lReplacePtr will the StrPtr of the string to do the replace with
'lReplacePos will be the string position (as in Mid$ etc.) to do the
replace
'lReplaceLenB will be LenB of strReplace
'----------------------------------------------------------------------------
Dim lMemPos As Long
lMemPos = (lStringPtr + lReplacePos * 2) - 2
CopyMemory ByVal lMemPos, _
ByVal lReplacePtr, _
lReplaceLenB
End Sub
The only other way I can see is with concatenation, so do Left$( etc. &
strReplace & Right$ etc.,
but that will be slow. The method with CopyMemory seems to work fine, but
ideally I would like
to avoid it as the error handling will be more tricky.
Is there a way to do this fast without CopyMemory?
RBS
> Looking for a fast way to replace at a given position a
> string within another string and it looks the only way is
> with CopyMemory:
Unless I've misread your question then you should be able to do what you
want using the native VB Mid statement, as in the following example:
Dim s1 As String, s2 As String
s1 = "1234567890123456789012345678901234567890"
s2 = "ABCDE"
Print s1
Mid$(s1, 20) = s2
Print s1
There is a third optional parameter, which I have not used above, enabling
you to specify how many characters to replace, otherwise the whole of s2
will be used. Post again if you meant something different.
Mike
RBS
"Michael Williams" <Mi...@WhiskeyAndCoke.com> wrote in message
news:uFyDEslr...@TK2MSFTNGP02.phx.gbl...
RBS
"Michael Williams" <Mi...@WhiskeyAndCoke.com> wrote in message
news:uFyDEslr...@TK2MSFTNGP02.phx.gbl...
Private Function ReplaceAt(strToSearch, strToFind, strReplace, lPos) As
String
'will replace strToFind in strToSearch with strReplace,
'but only if strToFind appears at position lPos
'------------------------------------------------------
Dim strTest As String
strTest = Mid$(strToSearch, lPos, Len(strToFind))
If strTest = strToFind Then
ReplaceAt = Left$(strToSearch, lPos - 1) & _
strReplace & _
Right$(strToSearch, Len(strToSearch) - (lPos +
(Len(strToFind) - 1)))
Else
ReplaceAt = strToSearch
End If
End Function
RBS
"RB Smissaert" <bartsm...@blueyonder.co.uk> wrote in message
news:O72am6lr...@TK2MSFTNGP05.phx.gbl...
In that case, you can use the Replace function. <g>
?replace("1234567", "4", "abc")
123abc567
If you need a VB5 implementation, here's one I stole from somewhere:
Public Function Replace(ByVal Expression As String, ByVal Find As String, ByVal
Replase As String, Optional Start As Long = 1, Optional Count As Long = -1, Optional
Compare As VbCompareMethod = vbBinaryCompare) As String
Dim nC As Long, nPos As Long
Dim nFindLen As Long, nReplaceLen As Long
nFindLen = Len(Find)
nReplaceLen = Len(Replase)
If (Find <> "") And (Find <> Replase) Then
nPos = InStr(Start, Expression, Find, Compare)
Do While nPos
nC = nC + 1
Expression = Left(Expression, nPos - 1) & Replase & Mid(Expression, nPos
+ nFindLen)
If Count <> -1 And nC >= Count Then Exit Do
nPos = InStr(nPos + nReplaceLen, Expression, Find, Compare)
Loop
End If
Replace = Expression
End Function
--
.NET: It's About Trust!
http://vfred.mvps.org
Sub test()
Dim str1 As String
Dim str2 As String
str1 = "123456789"
str2 = "XX"
str1 = Replace(str1, "4", str2, 4, 1)
'I need result to be "123XX56789"
'but will get "XX56789
MsgBox str1
End Sub
RBS
"Karl E. Peterson" <ka...@mvps.org> wrote in message
news:eFSc1amr...@TK2MSFTNGP04.phx.gbl...
Well, I'm not sure what exactly you're overlooking, but when I do this in the
Immediate Window:
?Replace("123456789", "4", "XX", 4, 1)
123XX56789
It seems to do what you say you want it to? Maybe it's that I'm taking what you say
you need too literally, and what you really need is what you allude you need? <g>
IOW, you don't care what's at position four, and it may be entirely non-unique, but
you need to replace it? Yeah, in that case, it's a mess. You can split and
concatenate. Or you can slide stuff around with CopyMemory. Is this something you
need to do repeatedly?
RBS
"Karl E. Peterson" <ka...@exmvps.org> wrote in message
news:%23Xc9MCn...@TK2MSFTNGP03.phx.gbl...
Here is one that will get the job done. You'd have to run timed tests to
see if its faster than concatenation.... (it should be...)
LFS
Private Sub Form_Load()
Debug.Print Replace("1234567", "4", "ABC")
Debug.Print Replace("1234321", "2", "ABC", 2)
Debug.Print Replace("1234321", "3", "XYZ", -1)
Debug.Print Replace("1234567", "345", "X")
Debug.Print Replace("1234321", "3", "XYZ", 1, 5)
End Sub
Function Replace(ByVal Source$, _
ByRef Find$, _
ByRef Insert$, _
Optional Repeat As Long = 1, _
Optional Position As Long = 0) As String
Dim tmp As String
Dim diff As Long
Dim begin As Long
Dim pos As Long
Dim all As Boolean
begin = 1
diff = Len(Insert) - Len(Find)
If Repeat < 0 Then
all = True
Repeat = 2
End If
If Position > 0 Then
pos = InStr(Position, Source, Find)
If pos = Position Then
Repeat = 1
begin = pos
Else
Repeat = 0
End If
End If
Do While Repeat > 0
pos = InStr(begin, Source, Find)
If pos > 0 Then
tmp = Space$(Len(Source) + diff)
Mid(tmp, 1) = Mid$(Source, 1, pos - 1)
Mid(tmp, pos + Len(Insert)) = Mid$(Source, pos + Len(Find))
Mid(tmp, pos) = Insert
begin = pos + Len(Insert)
Repeat = Repeat - 1
If all Then Repeat = 2
Source = tmp
Else
Repeat = 0
End If
Loop
Replace = Source
End Function
RBS
"Larry Serflaten" <serf...@usinternet.com> wrote in message
news:%23MNOaOn...@TK2MSFTNGP06.phx.gbl...
Yes, look at the debug examples to see it in action.
One test that I did not include in the post is the case where the
inserted text contains the search text, for example:
Debug.Print Replace("123345", "3", "A3B", -1)
There, the insert text (A3B) contains the find text (3), but the
function will not loop forever, once the find text has been replaced,
it moves on.... The result will be "12A3BA3B45"
LFS
> Here is one that will get the job done. You'd have to run timed tests to
> see if its faster than concatenation.... (it should be...)
It will have to be amended to catch the case where the find text is at
the very end of the source string. The earlier version errors, this version
catches that condition before it occurs:
LFS
Do While Repeat > 0
If pos < Len(Source) Then
Mid(tmp, pos + Len(Insert)) = Mid$(Source, pos + Len(Find))
End If
Function Substitute(FullText As String, Position As Long, _
Length As Long, NewText As String) As String
Substitute = FullText
Mid(Substitute, Position) = String(Length, Chr$(1))
Substitute = Replace(Substitute, String(Length, Chr$(1)), NewText)
End Function
Of course, a final version should probably have some kind of error testing I
suppose.
--
Rick (MVP - Excel)
"Karl E. Peterson" <ka...@exmvps.org> wrote in message
news:%23Xc9MCn...@TK2MSFTNGP03.phx.gbl...
--
Rick (MVP - Excel)
"Rick Rothstein" <rick.new...@NO.SPAMverizon.net> wrote in message
news:O9l2hnor...@TK2MSFTNGP02.phx.gbl...
Function Substitute(FullText As String, Position As Long, _
Length As Long, NewText As String) As String
Substitute = Left(FullText, Position - 1) & NewText & _
Mid(FullText, Position + Length)
End Function
--
Rick (MVP - Excel)
"Rick Rothstein" <rick.new...@NO.SPAMverizon.net> wrote in message
news:uuTHCsor...@TK2MSFTNGP05.phx.gbl...
Karl,
You get 123XX56789 if you use your implementation of the Replace function
for VB5, but if you use the buit in Replace function of VB6, strangely you
get XX56789 (it discards all the characters to the left of the Start
parameter).
I don't think the VB6 function should work in this way, and I think it's
most likely a bug.
I would had swear that the VB6 function worked as your VB5 implementation
does, but I see it's not the case.
> You get 123XX56789 if you use your implementation of the
> Replace function for VB5, but if you use the buit in Replace
> function of VB6, strangely you get XX56789 (it discards all
> the characters to the left of the Start parameter). I don't think
> the VB6 function should work in this way, and I think it's most likely a
> bug.
Actually that's the way the VB6 Replace function is supposed to work. Here's
the appropriate extract from the help files:
"The return value of the Replace function is a string, with
substitutions made, that begins at the position specified by
start and and concludes at the end of the expression string.
It is not a copy of the original string from start to finish."
Mike
A little counterintuitive to me.
Do you understand the reason?
PS: I rather would call it CutAndReplace.
Yes. Never was aware of this behaviour and I will need to check all my code
to make sure it isn't causing a problem somewhere. I always thought that the
Start argument meant that it would start looking for the Find argument from
the Start position. Strange one that.
RBS
"Eduardo" <m...@mm.com> wrote in message news:gqinet$3sa$1...@aioe.org...
Function ReplaceAt(strToSearch As String, _
strToFind As String, _
strReplace As String, _
lPos As Long, _
Optional bOnlyWithFind As Boolean = True) As String
'will replace strToFind in strToSearch with strReplace,
'but only if strToFind appears at position lPos if bOnlyWithFind = True
'or replace in any case, no matter what is at that position
'----------------------------------------------------------------------
If bOnlyWithFind Then
If Mid$(strToSearch, lPos, Len(strToFind)) <> strToFind Then
ReplaceAt = strToSearch
Exit Function
End If
End If
If Len(strToFind) = Len(strReplace) Then
'this is a lot faster that concatenation
'note though that this will alter strToSearch and
'and passing that ByVal will make it about 50% slower
'----------------------------------------------------
Mid$(strToSearch, lPos, Len(strToFind)) = strReplace
ReplaceAt = strToSearch
Else
ReplaceAt = Left$(strToSearch, lPos - 1) & _
strReplace & _
Right$(strToSearch, Len(strToSearch) - (lPos +
(Len(strToFind) - 1)))
End If
End Function
And tested like this:
Sub test()
Dim i As Long
Dim str1 As String
Dim str2 As String
Dim str3 As String
str1 = String(100, "A")
str2 = "123"
StartSW
For i = 1 To 100000
str3 = ReplaceX(str1, "A", str2, 1, 50)
'str3 = ReplaceAt(str1, "A", str2, 50)
Next i
StopSW
MsgBox str3, , Len(str3)
End Sub
I suppose it could be made faster by using one of the fast string concat
routines that are available.
RBS
"Larry Serflaten" <serf...@usinternet.com> wrote in message
news:erjJjbnr...@TK2MSFTNGP04.phx.gbl...
You seem to be making a big meal out of it.
Firstly let's see if I have the problem correctly:
You have a string and at a given position you want to remove some characters
and insert some others, the number of inserted and removed characters need
not be equal and there will only be one set of characters to replace.
If that's the case a quick method would be firstly calculate the length of
the final string then make a new string of that length. Then using Mid copy
the bits you want from the source string to the result string then again
using Mid plonk the new text in the gap that's waiting for it. All done -
Easy.
Good Luck
Dave O.
Not sure what gives you that idea. I am just saying that the suggested code
is not
faster than what I posted. You are probably right in that prefixing a string
and doing Mid etc.
is faster than doing the concatenation as posted. Will test that now.
RBS
"Dave O." <nob...@nowhere.com> wrote in message
news:%237dbwUv...@TK2MSFTNGP06.phx.gbl...
My example may be slower due to all the extra conditions it covered.
If you'll notice, the meat of the function did exactly as you indicate above;
allocate one large string and Mid copy the parts into it:
(Comments added)
' Allocate one large string
> tmp = Space$(Len(Source) + diff)
' Copy left side
> Mid(tmp, 1) = Mid$(Source, 1, pos - 1)
' Copy right side
> If pos < Len(Source) Then
> Mid(tmp, pos + Len(Insert)) = Mid$(Source, pos + Len(Find))
> End If
' Copy new text
> Mid(tmp, pos) = Insert
None the less, I think streamlining that approach would be your best
'all VB' approach....
Good luck!
LFS
Check these alternative Replace functions, modify as needed:
http://www.xbeat.net/vbspeed/c_Replace.htm
VB6 Replace features a very bizarre interpretation of the Start parameter
that can be paraphrased as follows:
' *before* any replacements
Replace = Mid$(Expression, Start)
Until anybody reveals the deeper meaning of this, we will not care about it
in our emulations.
RBS
"Nobody" <nob...@nobody.com> wrote in message
news:%23L8YKUw...@TK2MSFTNGP05.phx.gbl...
> BTW, this is what they say about the Start argument
> in the regular VB6 replace, and I agree:
> VB6 Replace features a very bizarre interpretation of the
> Start parameter that can be paraphrased as follows:
> ' *before* any replacements
> Replace = Mid$(Expression, Start)
> Until anybody reveals the deeper meaning of this, we
> will not care about it in our emulations.
Well, yes, I certainly do agree that it is rather stange behaviour. But is
/is/ documented and it /is/ the way it works, so if you do decide to use the
VB6 Replace function in your code then you must take that behaviour into
account, like it or not.
Mike
Hard to disagree with that one :-)
RBS
"Michael Williams" <Mi...@WhiskeyAndCoke.com> wrote in message
news:%23ngEAGy...@TK2MSFTNGP03.phx.gbl...
I don't agree on this point.
If you were going to distribute this Replace function to everybody as a
direct replacement of the built in VB6 one, I agree, but if you are going
to use it in your programs, I don't agree that you necessary have to emulate
the VB6 one in all and every aspects.
If you do it for yourself, you can do it as you like better.
Even if you were going to distribute it, you can write a note stating that
there is such a difference.
I want to add something:
Of course both options have advantages and disadvantages.
If you fully emulates the VB6 function, the advantage is that if you later
decide to remove the function replacement, all the code will remain working.
On the other hand, if you don't emulate it, you can use the replacement
function in situations like this one that "RB Smissaert" is posting about,
and that the VB6 one is not suited for.
Public Function ReplaceX(ByVal strSource As String, _
ByVal strFind As String, _
ByVal strReplace As String, _
Optional ByVal lStart As Long = 1, _
Optional ByVal lCount As Long = -1, _
Optional ByVal bCompare As VbCompareMethod =
vbBinaryCompare) As String
'could make this a bit faster by making it a Sub and putting the result in
a ByRef argument
'------------------------------------------------------------------------------------------
Dim i As Long
Dim lPos As Long
Dim lLenFind As Long
lPos = InStr(lStart, strSource, strFind, bCompare)
If lPos = 0 Then
'strFind is not in strSource, so return strSource and get out
'------------------------------------------------------------
If lStart = 1 Then
ReplaceX = strSource
Else
'to make it consistent with the normal Replace function
'------------------------------------------------------
ReplaceX = Mid$(strSource, lStart)
End If
Exit Function
End If
lLenFind = Len(strFind)
If lStart < lPos And lLenFind = Len(strReplace) Then
If lCount = 1 Then
Mid$(strSource, lPos) = strReplace
Else
Do While lPos > 0
Mid$(strSource, lPos, lLenFind) = strReplace
lPos = InStr(lPos + lLenFind, strSource, strFind, bCompare)
Loop
End If
If lStart = 1 Then
ReplaceX = strSource
Else
'to make it consistent with the normal Replace function
'------------------------------------------------------
ReplaceX = Mid$(strSource, lStart)
End If
Else
ReplaceX = Replace(strSource, strFind, strReplace, lStart, lCount,
bCompare)
End If
End Function
RBS
"RB Smissaert" <bartsm...@blueyonder.co.uk> wrote in message
news:OH6t2flr...@TK2MSFTNGP02.phx.gbl...
> Looking for a fast way to replace at a given position a string within
> another string
> and it looks the only way is with CopyMemory:
>
> Private Declare Sub CopyMemory _
> Lib "kernel32" _
> Alias "RtlMoveMemory" _
> (pDst As Any, _
> pSrc As Any, _
> ByVal ByteLen As Long)
>
> Sub ReplaceAt(lStringPtr As Long, _
> lReplacePtr As Long, _
> lReplacePos As Long, _
> lReplaceLenB As Long)
>
> 'lStringPtr will the StrPtr of the string to do the replace in
> 'lReplacePtr will the StrPtr of the string to do the replace with
> 'lReplacePos will be the string position (as in Mid$ etc.) to do the
> replace
> 'lReplaceLenB will be LenB of strReplace
>
> '----------------------------------------------------------------------------
> Dim lMemPos As Long
>
> lMemPos = (lStringPtr + lReplacePos * 2) - 2
>
> CopyMemory ByVal lMemPos, _
> ByVal lReplacePtr, _
> lReplaceLenB
>
> End Sub
>
> The only other way I can see is with concatenation, so do Left$( etc. &
> strReplace & Right$ etc.,
> but that will be slow. The method with CopyMemory seems to work fine, but
> ideally I would like
> to avoid it as the error handling will be more tricky.
> Is there a way to do this fast without CopyMemory?
>
>
> RBS
>
>> [Mike Williams said] Well, yes, I certainly do agree that it is
>> rather stange behaviour. But is /is/ documented and it /is/ the
>> way it works, so if you do decide to use the VB6 Replace
>> function in your code then you must take that behaviour into account,
>> like it or not.
>
> [Eduardo said] I don't agree on this point. If you were going to
> distribute this Replace function to everybody as a direct
> replacement of the built in VB6 one, I agree, but if you are
> going to use it in your programs, I don't agree that you
> necessary have to emulate the VB6 one in all and every aspects.
You have not read my post properly, Eduardo. I never said that a coded
function to replace parts of a string should behave in the same way as the
VB6 Replace function. I did NOT say that, or anything remotely like it. I
was simply commenting on RB Smissaert's observation that the author of some
specific code made the comment, "VB6 Replace features a very bizarre
interpretation of the Start parameter". I agreed with both the author of the
code and with RB Smissaert in that the VB6 Replace function's interpretation
of the Start parameter is indeed bizarre, and I said:
But is /is/ documented and it /is/ the way it works, so if you
do decide to use the VB6 Replace function in your code then
you must take that behaviour into account, like it or not
The above is /exactly/ what I said. I specifically mentioned the VB6 Replace
function, and I stand by my statement that if you are going to use the VB6
Replace function in your code then you must take its behaviour into account.
Naturally if you write your own code to perform a specific task and if you
are not offering it as a direct replacement for a native built in function
then you are free to write it so that it behaves in any way you wish, but I
never mentioned the behaviour of coded solutions in my post, I was
specifically talking about what you should accept if you /do/ decide to use
the VB6 Replace function. You have misinterpreted what I said, Eduardo.
Mike
> You have not read my post properly, Eduardo. I never said that a coded
> function to replace parts of a string should behave in the same way as the
> VB6 Replace function. I did NOT say that, or anything remotely like it. I
> was simply commenting on RB Smissaert's observation that the author of
> some specific code made the comment, "VB6 Replace features a very bizarre
> interpretation of the Start parameter". I agreed with both the author of
> the code and with RB Smissaert in that the VB6 Replace function's
> interpretation of the Start parameter is indeed bizarre, and I said:
>
> But is /is/ documented and it /is/ the way it works, so if you
> do decide to use the VB6 Replace function in your code then
> you must take that behaviour into account, like it or not
>
> The above is /exactly/ what I said. I specifically mentioned the VB6
> Replace function, and I stand by my statement that if you are going to use
> the VB6 Replace function in your code then you must take its behaviour
> into account.
>
> Naturally if you write your own code to perform a specific task and if you
> are not offering it as a direct replacement for a native built in function
> then you are free to write it so that it behaves in any way you wish, but
> I never mentioned the behaviour of coded solutions in my post, I was
> specifically talking about what you should accept if you /do/ decide to
> use the VB6 Replace function. You have misinterpreted what I said,
> Eduardo.
Yep, I had read it too fast.
Wow. So, uh, well, that's just weird.
> I don't think the VB6 function should work in this way, and I think it's
> most likely a bug.
> I would had swear that the VB6 function worked as your VB5 implementation
> does, but I see it's not the case.
I thought I *was* using VB's replace, when I posted the above. I must've had the
replacement function in whatever application I had open in the IDE at the time. I
agree, it makes more sense the way I presented it. <G>
(Actually, "my" replacement has its roots over at vbSpeed, as I recall. Whaddaya
bet they're all "wrong" too?)
But documented, "The return value of the Replace function is a string, with
substitutions made, that begins at the position specified by start and and
concludes at the end of the expression string." Also If start >
Len(expression) Replace returns Zero-length string.
David
Yeah, I saw that. Hadn't before. Weird. :-|