字符串里包含很多空格"aa bb ee dd ff 2332 898f 2e 23",有什摸好办法快速删除? ( 积分: 10 )

  • 主题发起人 主题发起人 xydrj
  • 开始时间 开始时间
X

xydrj

Unregistered / Unconfirmed
GUEST, unregistred user!
字符间相隔就一个空格。其实我是想把空格去掉,然后把16进制转成10进制数。
 
字符间相隔就一个空格。其实我是想把空格去掉,然后把16进制转成10进制数。
 
AnsiReplaceText('你字符串',' ','');
 
StringReplace();
 
function delstrblank(astr: String): String;
var
i: Integer;
s: String;
begin
Result:='';
for i:=0 to length(astr) do
begin
s:=copy(astr,i,1);
if s<>' 'then
Result := Result + s;
end;
end;
 
CZCN,你这段代码效率可是真不咋地啊
 
用stringplace().就可以了。
 
消除str字符串中的空格!
var
str:string;
index,j:integer;
begin
j:=length(str);
while j>0 do
begin
index:=pos(' ',str);
delete(str,index,1);
j:=j-1;
end;
此时得到的str就没有空格了
 
方法都不怎么样啊?
 
最简单的就是用stringplace()将空格替换成''
 
这样是不是好些?
procedure ss(var s:string);
var
i,j:integer;
begin
j := 1;
for i := 1 to length(s) do
begin
if s<>' ' then
begin
if j <> i then s[j] := s;
inc(j);
end;
end;
setlength(s,j-1);
end;
 
无泪

你的代码改成
var
str:string;
index,j:integer;
begin
index:=pos(' ',str);
while index>0 do
begin
delete(str,index,1);
index:=pos(' ',str);
end;
end;
才是比较正确的写法。
不过我觉得效率低了点,每次使用pos,还要从字符串的起始位置去搜索空格,有点浪费。
直接逐字搜索,可能效果更好,一次搜索就完成。没有浪费的对比。
 
又看到此帖,既然说到效率,就小小测试了一下
function ss(var s:string):integer;//改了下代码顺便统计下空格数
var
i,j:integer;
begin
j := 1;
Result := length(s);
for i := 1 to Result do
begin
if s<>' ' then
begin
if j <> i then s[j] := s;
inc(j);
end;
end;
setlength(s,j-1);
Result := Result - j + 1;
end;
找了个文件测试,721550字节,空格:67912,结果:
我 :20ms左右
无泪:等了10分钟,放弃,终止运行时j=634820
monkeyking1983:等了2分钟,也放弃

然后找了小点的文件测试:
长度 空格
3746 | 592
无泪 60ms
monkeyking1983 10

长度 空格
35532 | 5292
无泪 5668ms
monkeyking1983 671ms

我的都是0ms

最后,用了个比较大的文件测试我的代码
长度 空格
39177434 | 921287
测试20次,最快1002ms,最慢1181ms,平均1140.8ms。

测试中感觉length函数比较慢,就又修改了下程序:
function ss2(var s:string):integer;
var
i,j:integer;
begin
j := 1;
Result := pinteger(integer(s)-4)^;//不用length了
for i := 1 to Result do
begin
if s<>' ' then
begin
if j <> i then s[j] := s;
inc(j);
end;
end;
setlength(s,j-1);
Result := Result - j + 1;
end;
测试20次,最快992ms,最慢1022ms,平均1004.7ms。

因为delphi对string的处理方式是copy on write,所以,在处理大字符串或循环次数多时,尽量不要用会写字符串的操作、函数,否则效率极低,而单纯检索一遍字符串的速度还是相当快的,38M的字符串,大约1″左右也就够了,我的机器PⅢ800+192M。
 
楼上的,你别把那些算法规到我头上啊,我可没有写任何代码。
哈哈。 我说了,那个用pos的方法绝对慢的。我提出来的思路和你是一样的。
 
如果不用汇编的话,这种可能简单一些(从后往前来):
procedure DeleteBlank(var s: string);
var
i: LongWord;
begin
i := Length(s);
while i > 0 do
begin
if s = #32 then Delete(s, i, 1);
Dec(i);
end;
end;
 
1983,pos是效率的一个原因,无泪的程序效率低的另外一大原因是delete,delphi对字符串处理是copy on write,也就是,每当修改字符串时,都会重新申请内存,700k的字符串,每次调用delete删除一个空格,都会导致重新申请700k内存、复制、释放这么一个过程,可以想像,处理721550|67912这样的字符串,会重复申请67912次700k内存,这是很大的一个开销。

凡是要引起修改字符串的操作,都不适用于较大量或较多次的字符串处理,楼上的代码也是同样,不防自己测试一下。
 
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
i, j: integer;
p: pchar;
begin
s := 'jkddjdjjd j dj j d j j jj j j j jj jj j j jj j j j jj j j jjjjjjjjjjj';
s := s + 'a'; //重要!

j := 0;
p:= pchar(s);
for i:= 0 to length(s) - 1 do
if p <> ' ' then
begin
p[j] := p;
inc(j);
end;
setLength(s, j + 1);
end;

非常快的拉,用一个PCHAR的转换越过字符串copy on write机制,且原地址操作呵
 
>>s := s + 'a'; //重要!

呵呵,“重要”处就是为了把s变成pchar后让i从0开始循环吗?既然知道copy on write,那s := s + 'a';似乎有违初衷,如果s足够大,就这一句就能让人等的不耐烦了,而且,只要有这句就不可能是“原地址操作”,s已经重新分配地址啦!
 
用汇编也很简单,速度未必是最快,但比非汇编快,注释一下,免得日后自己看了记不起来。顺便请问楼主打算怎么分掉这10分呢? 呵呵

function Kill32(StrPoint:Pointer; StrLong:Integer):Integer;
asm
PUSH EDI //保留这些寄存器进栈
PUSH ESI
PUSH EBX
MOV EDI,EAX //设置目标和源指针,指向字串的第一个字节
MOV ESI,EAX
MOV ECX,StrLong //设置循环长度,即字串长度
XOR EBX,EBX //初始化目标长度计数器,记录字串处理后的长度
@@J2: //循环体开始
MOV AL,[ESI] //取一个字节
CMP AL, 32 //32是空格的编码
JZ @@J1 //是空格则跳过,不处理
MOV [EDI],AL //非空格,则保存到目标指针的位置
INC EDI //目标指针加一
INC EBX //目标长度计数器加一
@@J1:
INC ESI //源指针加一
LOOP @@J2 //执行循环体
MOV RESULT,EBX //返回处理后字串的长度
POP EBX //从栈中恢复寄存器
POP ESI
POP EDI
end;

调用例子
var
s:string;
begin
s := '1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l ';
L := Kill32(@S[1], Length(S));
SetLength(S, L);
......
end;
 
如果字串是String类型,那么可以省掉length,但多了几个汇编指令,反而会慢了点

function Kill32(StrPoint:Pointer):Integer;
asm
PUSH EDI //保留这些寄存器进栈
PUSH ESI
PUSH EBX
MOV EDI,EAX //设置目标和源指针,指向字串的第一个字节
MOV ESI,EAX
MOV ECX,StrLong //设置循环长度,即字串长度
XOR EBX,EBX //初始化目标长度计数器,记录字串处理后的长度
@@J2: //循环体开始
MOV AL,[ESI] //取一个字节
OR AL,AL //字串是否结束
JZ @@J3
CMP AL, 32 //32是空格的编码
JZ @@J1 //是空格则跳过,不处理
MOV [EDI],AL //非空格,则保存到目标指针的位置
INC EDI //目标指针加一
INC EBX //目标长度计数器加一
@@J1:
INC ESI //源指针加一
JMP @@J2 //执行循环体
@@J3:
MOV RESULT,EBX //返回处理后字串的长度
POP EBX //从栈中恢复寄存器
POP ESI
POP EDI
end;

调用例子
var
s:string;
begin
s := '1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l ';
L := Kill32(@S[1]);
SetLength(S, L); //在汇编程序里面完全可以给处理结果填写结束符
//但考虑到是在使用Delphi写程序而不是汇编
//要照顾它的内存分配,所以保留这行
......
end;
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
582
import
I
I
回复
0
查看
763
import
I
I
回复
0
查看
881
import
I
后退
顶部