首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

替换字符串中的关键字,速度非常慢.有什么好办法?该如何解决

2012-01-06 
替换字符串中的关键字,速度非常慢.有什么好办法??strcontent为长字符串.FFreeFileOpenapp.path&\mystr.i

替换字符串中的关键字,速度非常慢.有什么好办法??
strcontent为长字符串.

F   =   FreeFile
Open   app.path   &   "\mystr.ini "   For   Input   As   #F
Do   Until   EOF(F)
Line   Input   #F,   str

' '将str替换成空
if   instr(strcontent,str)> 0   then
    strcontent=replace(strcontent,str, " ")
end   if

' '其他字符与str组合,再过滤
strtemp=   "AA "   &   str
if   instr(strcontent,strtemp)> 0   then
    strcontent=replace(strcontent,strtemp, " ")
end   if

strtemp=   str   &   "BB "  
if   instr(strcontent,strtemp)> 0   then
    strcontent=replace(strcontent,strtemp, " ")
end   if

strtemp=   str   &   "CC "   &   "899 "
if   instr(strcontent,strtemp)> 0   then
    strcontent=replace(strcontent,strtemp, " ")
end   if

......
......
......
......
......
......组合过滤比较多

loop

在mystr.ini里,每行是一个关键字,大概有6000行.全部循环完,感觉非常慢.请问有什么好一点办法嘛???

[解决办法]
组合过滤比较多的话是不是可以组合下

不过不知道这样的效率有没有提高

至少代码少了的
[解决办法]
你看看逻辑
if instr(strcontent,str)> 0 then
strcontent=replace(strcontent,str, " ")
你在这里已经把str替代结束了,怎么能找到 "AA " & str的字符串呢?你后面那些能找到么?
end if

' '其他字符与str组合,再过滤
strtemp= "AA " & str
if instr(strcontent,strtemp)> 0 then
strcontent=replace(strcontent,strtemp, " ")
end if

也许我分析错了,你再看看

实在不行就给客户一个进度条
[解决办法]
不要判断,直接调用 replace
[解决办法]
你替换的规则是怎么样?
是在mystr.ini中的任一行数据str,
把这三种组合 "AA " & str,str & "BB " 和str & "CC899 "的字符串
都替换为 " "吗?
[解决办法]
For VB5 user:
Public Sub ReplaceAll(ByRef sOrigStr As String, _
ByVal sFindStr As String, _
ByVal sReplaceWithStr As String, _
Optional bWholeWordsOnly As Boolean)
'
' Replaces all occurances of sFindStr with sReplaceWithStr
'
Dim lPos As Long
Dim lPos2 As Long
Dim sTmpStr As String
Dim bReplaceIt As Boolean
Dim lFindStr As Long


On Error GoTo vbErrorHandler

lFindStr = Len(sFindStr)

lPos2 = 1
bReplaceIt = True
sTmpStr = sOrigStr

Do
lPos = InStr(lPos2, sOrigStr, sFindStr)
If lPos = 0 Then
Exit Do
End If
If bWholeWordsOnly Then
On Error Resume Next
If lPos = 1 Or (Mid$(sOrigStr, lPos - 1, 1) = " ") Then
If (Mid$(sOrigStr, lPos + lFindStr, 1) = " ") Or Mid$(sOrigStr, lPos + lFindStr + 1, 1) = " " Then
bReplaceIt = True
Else
bReplaceIt = False
End If
End If
End If
If bReplaceIt Then
If lPos > 1 Then


sTmpStr = Left$(sOrigStr, lPos - 1)
Else
sTmpStr = " "
End If
sTmpStr = sTmpStr & sReplaceWithStr
sTmpStr = sTmpStr & Mid$(sOrigStr, lPos + lFindStr, Len(sOrigStr) - (lPos + lFindStr - 1))
sOrigStr = sTmpStr
End If
lPos2 = lPos + 1
Loop
sOrigStr = sTmpStr
Exit Sub

vbErrorHandler:
Err.Raise Err.Number, "StrHandler ReplaceAll ", Err.Description


End Sub

[解决办法]
不要判断,直接调用 replace
[解决办法]
这种问题想快都难。

6000条内容,再加上N种组合,6000*N 次循环,还是处理VB不善长的大字符串处理,加进度条吧!

另外,少一个 instr() 判断应该会快许多。

[解决办法]
不知道楼主什么意图,在测试VB的效率?

如果是真想实用,单看楼主写的那些,简直是天方夜谭,程序绝对没这么写的.
[解决办法]
replace函数
[解决办法]
楼主考虑一下正则表达式

--------
www.vicmiao.com
努力就有美好时光!
[解决办法]
vb里不可以用正则么?
[解决办法]
可以将文件读入一个字符串变量,然后再对该字符串变量进行replace操作,如果应用中需要每一行的数据,再用split函数分解。这样避免在循环中频繁调用replace函数,replace函数可以将字符串中所有要替换的内容一次性完成。
希望这个思路与你的应用不冲突!
[解决办法]
这样:
每读出一句的判断还是要的。因为你的所有组合,都是包含 str 的,因此若长字符串不包含 str ,其他的所有操作都可以省掉,直接处理下一句。

F = FreeFile
Open app.path & "\mystr.ini " For Input As #F
Do Until EOF(F)
Line Input #F, str

if instr(strcontent,str) then
strcontent=replace(strcontent, "AA " & str, " ")
strcontent=replace(strcontent,str & "BB ", " ")
strcontent=replace(strcontent,str & "CC " & "899 ", " ")
strcontent=replace(strcontent,str, " ")
end if

loop
Close #F
[解决办法]
AA,BB.....这些处理一次就行了吧?为什么要放在每一个line中?
[解决办法]
AA,BB这些也是变量?
[解决办法]
AA,BB.....这些处理一次就行了吧?为什么要放在每一个line中?
-------------------------
哦,是我糊涂了 !
[解决办法]
都成头条了!
[解决办法]
不可能有大幅度的改进。字符串处理本身就很慢。再就上要对一个长字符串反复处理。

能否说说你要干什么?看看能否采用其他方案。
[解决办法]
想不通为什么楼主要一行一行的读文件,慢的不是处理字符串,而是循环读文件。

Dim i As Integer
Dim v() As Byte
Dim s As String

i = FreeFile()

Open App.Path & "\mystr.ini " For Binary As i
ReDim v(LOF(i) - 1)
Get i, , v()
Close i

s = StrConv(v, vbUnicode)

s = Replace(s, "AA ", " ")
s = Replace(s, "BB ", " ")
s = Replace(s, "CC899 ", " ")
' ...

你用这种方式来看看速度如何。


[解决办法]
呵呵,有些同学看代码不仔细啊!
楼主的目的显然不是要处理 mystr.ini 这个文件,而是要使用它里面内容作为的配对条件。所以一次性读取文件和一行行读取差距不会太明显。

of123 的方法是可以改进不少的,因为 str 如果不存在,其它的配对就不会存在。加一个判断后能大幅减速少判断次数!!

加进度条不会增加处理速度,但能使界面友好,感觉就会“快”一些。关键字数量未知很容易解决,先计算出 ini 文件的行数就可以了。


[解决办法]
接着fj182(阿花) 的写下去
dim b() as string
dim i as long
dim u as long
b=split(s,vbcrlf)
u=ubound(b)
for i=0 to u
strcontent=b(i)

next i
用这方法得到的strcontent和楼主在do循环中的strcontent有什么区别?
正如楼上所说,楼主不是要处理mystr.ini文件,但是,首先,用fj182(阿花) 的方式与每行读取的方式与逐行读文件的方式速度不在一个数量级,其二,避免了在循环中用replace,这肯定可以加快处理速度的,即使后面再用循环取strcontent,也只是相当于楼主的do循环次数,但少了replace操作。
[解决办法]
改正:
正如楼上所说,楼主不是要处理mystr.ini文件,但是,首先,用fj182(阿花) 的方式与逐行读文件的方式速度不在一个数量级,其二,避免了在循环中用replace,这肯定可以加快处理速度的,即使后面再用循环取strcontent,也只是相当于楼主的do循环次数,但少了replace操作。

[解决办法]
如果想提速,就只能在VB的内置函数上下功夫了。这个6000*N的LOOP再减,也还是很大的。
重写一下INSTR函数,我记得网上有人贴过这个算法,速度会提高很多。
[解决办法]
看一下如下例子体会一下replace一次进行多次替换的效果:
Dim s As String
s = "adfasfsffsfsaf "
Debug.Print Replace(s, "a ", "X ")
相信上述例子中的替换速度比用下面的速度快
for i=1 to len(s)
t=mid(s,i,1)
t=replace(t, "a ", "X ")
newStr=newStr & t
next i

实际上就替换操作来说,本来只用调用N次的,但在楼主的思路中可能要调用6000*N次。这就像登山,有索道直接上山顶,但如果要绕着上去,无论是走路还是开车,也快不了的。
[解决办法]
我搞不懂楼主的逻辑关系。
1、将str替换成空
2、其他字符与str组合,再过滤
这第一步已经把str消灭了,后面的组合就不存在了。
strtemp= "AA " & str
等于是 strtemp= "AA " & " "
等于是 strtemp= "AA "
楼主可能是要先消灭组合的,最后消灭str。如果是这样,又有一个麻烦, "AA " & str & "BB ",怎么考虑?
[解决办法]
1、其实慢的不是比较的速度,而是字符串被改变重新分配内存的速度。因此建议楼主使用定长字符串,足够空间的定长字符串,这肯定会提高速度。象strcontent就可以声明为全局的,减少临时字符串的使用。
2、再就是尽力不使用会产生临时字符串的函数。比如类似strcontent = replace()。可以使用Instr函数替代,找到位置后用自己的replace函数。自己的replace函数使用copymemory,速度是很快的。总之就是减少内存分配的次数。
3、另外还有一个办法就是优化关键字数据结构。这个方法很多的,比如树状结构。
[解决办法]
Split之后再进行Join
[解决办法]
回vbman2003(家人):
看倒是没看错,只不过后来他改进了。
同意VBToy(无证编程):
“本来只用调用N次的,但在楼主的思路中可能要调用6000*N次”
Replace是很快的,我试过:200多K的文本,调用80次,替换了几千个数据,毒龙850CPU,一秒之内完成。
[解决办法]
对整个 mystr.ini 进行替换,干嘛要一行一行进行?关键词组合N多,就替换 N 次嘛。
[解决办法]
主要原因是每一次替换都要对整个字符串进行重写。把该字符串读入bit数组当中,再操纵数组,每次替换就只变化一个字节。速度就快了
Dim b() as Byte,
b() = "source "

[解决办法]
1 读取整个文档,进行替换
2 要替换的关键字要考虑考虑,如先替换 str,哪么再替换 "AA "就行了,不用再替换 "AA " & str,替换关键字越短,速度越快!
3 不用instr查找了,替换和查找差不多是一个过程,你一个过程重复两次,没有意义
[解决办法]
呵!一个多月没来,想不到赶上了这么热闹的一个贴子!这热闹我一定要凑凑^_^

问题很绕人,看了前面各位高见,我所想到的第一步优化,已被提过了:
就是对硬盘IO的读取越少越好,的确,IO速度相对内存速度来说根本不在一个数量级,而每次从硬盘读1Byte与1MByte确是同一数量级的耗时,减少IO操作次数,当然是首选优化;

当然,光这一点是不够的,因为这个代码集中了两种低速操作,IO读写与变长字符串再赋值,前者优化了,后者在这里也是回避不了的,我觉得当务之急还是应该减少循环的次数!



LZ的思路有一个漏洞:先后替换,会造成误杀,
比如:strcontent包括如下内容:
“关键AA关键字1字2”
当你替换完“AA关键字1”后,strcontent就变成了“关键字2”,这样本不包含的“关键字2”,会在下轮替换中被误杀了。

我想换一个思路来解决,那就是,先将所有关键字替换成一个统一的、不可能在关键字中出现的固定字串,如:“%#%$^%^^&^%^%^*&&*”,然后,再将“AA”、“BB”之类的,与它组合在最后分别替换。
简单算一下:原来的循环量是6000*N次,而采用上述方案后,循环量只有6000+N次,速度几乎可提高N倍。

示例:
Open App.Path & "\mystr.ini " For Binary As i
ReDim v(LOF(i) - 1)
Get i, , v()
Close i
s = StrConv(v, vbUnicode)

b = Split(s, vbCrLf)
u = UBound(b)
For ii = 0 To u
strcontent = replace(strcontent,b(ii), "%#%$^%^^&^%^%^*&&* ")
Next ii
strcontent = replace(strcontent, "AA%#%$^%^^&^%^%^*&&* ", " ")
strcontent = replace(strcontent, "BB%#%$^%^^&^%^%^*&&* ", " ")
strcontent = replace(strcontent, "CC%#%$^%^^&^%^%^*&&* ", " ")
....
strcontent = replace(strcontent, "%#%$^%^^&^%^%^*&&* ", " ")

LZ说原代码要3秒多,这样一改应该在1秒以下了吧。速度快了,误杀也可避免了(当然也不是绝对避免,只是概率要小得多)不知,各位以为如何?

[解决办法]
补充:
其实使用像 "%#%$^%^^&^%^%^*&&* " 这样长的标记串,可能没必要,在正常文本中是不会出现vbNullChar字符(即Chr$(0))的,除非LZ对字符串有特殊需要,否则最佳的标记串就用这一个字符即可,理论上,这也会提升替换速度。具体效果,LZ可自己试试。
[解决办法]
若最多只会有一个关键字被替换,那你这个问题就非常简单了。因为,这个代码,速度慢在String的不断重新赋值上,尤其是当原串很长时,会极慢的。按你这么一说,代码可很简单!

程序流程这样写:
For ii = 0 To u
if instr(1,strcontent,b(ii))> 0 then exit for
Next
if ii <=u then
if instr(1,strcontent, "AA " & b(ii))> 0 then
strcontent = replace(strcontent, "AA " & b(ii), " ")
exit sub
end if
if instr(1,strcontent, "BB " & b(ii))> 0 then
strcontent = replace(strcontent, "BB " & b(ii), " ")
exit sub
end if
......
strcontent = replace(strcontent, b(ii), " ")
end if

还有,你可以将准备用于组合的“AA”、“BB”之类的字符串,预先存入数组,那后面这段就可用一个循环搞定了,不用写那么多代码。

replace不管是否替换了内容,都会引起字符串重新赋值,所以先用instr很有必要!instr是很快的,前面那个6000次循环查找,在大多数机器上都是10毫秒以下的操作,后面最多也只有一次replace重新赋值,所以我预测,这样的代码在主流机器上运行,不应该超过10毫秒。没有什么必要再需优化的了。

要见识instr的速度,你可参见下面的贴子:
http://community.csdn.net/Expert/topic/5603/5603824.xml?temp=.6377832
这个贴子里,我测试过的代码,查找5M长的字串,得出几百万个结果,也不过几十毫秒,你这个就更不在话下了。
[解决办法]
请注意,instr 的速度相当的快!!!

但是应该这么写:

L = instr(XXX,YYY)

如果你用 instr(XXX,YYY) ,则速度会慢很多倍。

热点排行