帮忙去掉数组中连续的00

keeley20 2011-07-06 06:15:55


求帮助,如上图,原始要处理的文件比较大,要求去掉连续的 00 字节,如果是单独一个0则保留,所有的非0都是有用数据。


我希望能输出如下图数据块(两边的00不要);




连续的00 段暂时没发现规律,希望各位大牛帮帮忙,万分感激。
...全文
215 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
keeley20 2011-07-07
  • 打赏
  • 举报
回复
谢谢楼上回复,你的代码作用和8楼 cngst的作用基本一样,整理出来后 所有数据都连接在了一起,比没有我说的分段。
我需要一段数据数据,如果中间两边都没有连续的00,则存为一行,

大图中 我希望得到 N 到 ) 之间为一行数据

第二行则是 第一个1 到 最后一个4 之间的数据

第三行 是 5 到 ? 之间的数据 依次类推
天涯倦客 2011-07-07
  • 打赏
  • 举报
回复

program Project5;

var
f: file of Byte;
i, j,k: Integer;
myfile: string;
BTemp, BTemp2: Byte;

begin

myfile := 'k:\toolscode\2.txt';
try
AssignFile(f, myfile);
Reset(f);
j := 0;
k:=FileSize(f);

try

for i := 1 to k -1 do
begin
seek(f, j);
Read(f, BTemp);
seek(f, i);
Read(f, BTemp2);
if (bTemp2 <> 0) or ((BTemp2 = 0) and (BTemp <> 0)) then
begin
j:=j+1;
seek(f, j );
write(f, BTemp2);
end;

end;
seek(f, j);
Truncate (f);
finally

end;


finally

CloseFile(f);

end;



end.

不过速度比较慢 一次读入内存操作 快些。。
只要比较当前的指针和下个以就行了。。
cngst 2011-07-07
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 keeley20 的回复:]

谢谢诸位的帮助,自己用笨的方法搞定了
Delphi(Pascal) code
if (buftmp[i]=#0) and (buftmp[i+1]=#0) and (buftmp[i+2]<>#0) then

判断段的开头
Delphi(Pascal) code
if (buftmp[i]<>#0) and (buftmp[i+1]=#0) and (buftmp[i+2]=#0) ……
[/Quote]

只要能解决问题,就是好方法
keeley20 2011-07-07
  • 打赏
  • 举报
回复
感谢各位的帮助,尤其是cngst,

代码写的不错,但还有个小问题没解决, 我需要连续的非00 一块块的输出。


图中我希望得到 N 到 ) 之间为一行数据

第二行则是 第一个1 到 最后一个4 之间的数据

第三行 是 5 到 ? 之间的数据

依次类推,还希望 cngst 能继续帮忙解决。
keeley20 2011-07-07
  • 打赏
  • 举报
回复
谢谢诸位的帮助,自己用笨的方法搞定了
if (buftmp[i]=#0) and (buftmp[i+1]=#0) and (buftmp[i+2]<>#0) then

判断段的开头
if (buftmp[i]<>#0) and (buftmp[i+1]=#0) and (buftmp[i+2]=#0) then

判断段的结尾 ,然后把中间的拷贝出来就行了。
cngst 2011-07-07
  • 打赏
  • 举报
回复
原来楼主是要分行啊,将上面的代码稍加改进就行了,下面是改进后的代码:



procedure TrimFileData(srcfile,dstfile:string);
const partlen=3072*1000;
var src,dst:pbyte;
filelen,lastpart,dstsize,lastiszero:dword;
filesrc,filedst:thandle;
i,partcnt:integer;

procedure ScanPart(param1:dword; var param2,param3:dword); assembler;
asm
pushad
mov esi,src
mov edi,dst
push edx
push ecx
mov edx,[ecx]
mov ecx,eax
shr ecx,1
xor ebx,ebx
@p1:
mov ax,word ptr[esi]
cmp ax,0
jz @p2
inc ebx
mov word ptr[edi],ax
mov dx,ax
add edi,2
jmp @p3
@p2:
cmp dx,0
jz @p3
mov ax,13
mov word ptr[edi],ax
mov ax,10
mov word ptr[edi+2],ax
add edi,4
add ebx,2
xor edx,edx
@p3:
add esi,2
loop @p1
shl ebx,1
pop ecx
mov [ecx],edx
pop edx
mov dword ptr[edx],ebx
popad
end;

begin
filesrc:=fileopen(srcfile,fmopenread);
if fileexists(dstfile) then deletefile(dstfile);
filedst:=filecreate(dstfile);
filelen:=getfilesize(filesrc,nil);
partcnt:=filelen div partlen;
lastpart:=filelen mod partlen;
getmem(src,partlen);
getmem(dst,partlen*2);
lastiszero:=0;
for i := 0 to partcnt - 1 do
begin
fileread(filesrc,src^,partlen);
scanpart(partlen,dstsize,lastiszero);
filewrite(filedst,dst^,dstsize);
end;
if lastpart>0 then
begin
fileread(filesrc,src^,lastpart);
scanpart(lastpart,dstsize,lastiszero);
filewrite(filedst,dst^,dstsize);
end;
fileclose(filesrc);
fileclose(filedst);
freemem(src);
freemem(dst);
end;




现在每段文字都会单独占一行了。
keeley20 2011-07-07
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 seamour 的回复:]

这就是 csdn 带星的高手的水平啊
[/Quote]
这位是说我吗? 本人delphi确实很菜,您可以看看我的勋章基本都是在Windows 板块拿的。

不懂就虚心请教我也不觉得有啥不对的,山外有山,你再厉害也有人比你强嘛。

如能这位大牛能解决我的问题,还望不吝赐教。
Seamour 2011-07-07
  • 打赏
  • 举报
回复
这就是 csdn 带星的高手的水平啊
天涯倦客 2011-07-07
  • 打赏
  • 举报
回复
设置指针 判断下就行了 写个循环。。
只允许2个byte间有一个0 是吧?
cngst 2011-07-06
  • 打赏
  • 举报
回复
狂晕,怎么上面粘贴上来的代码不是最新的,难道我忘记重新复制最新代码了?!

真正最新修改好的代码:


procedure TrimFileData(srcfile,dstfile:string);
const partlen=3072*1000;
var src,dst:pbyte;
filelen,lastpart,dstsize:dword;
filesrc,filedst:thandle;
i,partcnt:integer;

procedure ScanPart(param1:dword; var param2:dword); assembler;
asm
pushad
mov esi,src
mov edi,dst
mov ecx,eax
shr ecx,1
xor ebx,ebx
@p1:
mov ax,word ptr[esi]
cmp ax,0
jz @p2
inc ebx
mov word ptr[edi],ax
add edi,2
@p2:
add esi,2
loop @p1
shl ebx,1
mov dword ptr[edx],ebx
popad
end;

begin
filesrc:=fileopen(srcfile,fmopenread);
if fileexists(dstfile) then deletefile(dstfile);
filedst:=filecreate(dstfile);
filelen:=getfilesize(filesrc,nil);
partcnt:=filelen div partlen;
lastpart:=filelen mod partlen;
getmem(src,partlen);
getmem(dst,partlen);
for i := 0 to partcnt - 1 do
begin
fileread(filesrc,src^,partlen);
scanpart(partlen,dstsize);
filewrite(filedst,dst^,dstsize);
end;
if lastpart>0 then
begin
fileread(filesrc,src^,lastpart);
scanpart(lastpart,dstsize);
filewrite(filedst,dst^,dstsize);
end;
fileclose(filesrc);
fileclose(filedst);
freemem(src);
freemem(dst);
end;




其实刚开始的错误很简单,太大意了,忘记将循环记数除2

cngst 2011-07-06
  • 打赏
  • 举报
回复
前面的函数,写好后就发过来了,没实际测试,刚才测试了一下,发现有个小问题,下面是修正版:



procedure TrimFileData(srcfile,dstfile:string);
const partlen=3072*1000;
var src,dst:pbyte;
filelen,lastpart,dstsize:dword;
filesrc,filedst:thandle;
i,partcnt:integer;

procedure ScanPart(param1:dword; var param2:dword); assembler;
asm
pushad
mov esi,src
mov edi,dst
mov ecx,eax
xor ebx,ebx
@p1:
mov ax,word ptr[esi]
cmp ax,0
jz @p2
inc ebx
mov word ptr[edi],ax
add edi,2
@p2:
add esi,2
loop @p1
shl ebx,1
mov dword ptr[edx],ebx
popad
end;

begin
filesrc:=fileopen(srcfile,fmopenread);
if fileexists(dstfile) then deletefile(dstfile);
filedst:=filecreate(dstfile);
filelen:=getfilesize(filesrc,nil);
partcnt:=filelen div partlen;
lastpart:=filelen mod partlen;
getmem(src,partlen*2);
getmem(dst,partlen*2);
for i := 0 to partcnt - 1 do
begin
fileread(filesrc,src^,partlen);
scanpart(partlen,dstsize);
filewrite(filedst,dst^,dstsize);
end;
if lastpart>0 then
begin
fileread(filesrc,src^,lastpart);
scanpart(lastpart,dstsize);
filewrite(filedst,dst^,dstsize);
end;
fileclose(filesrc);
fileclose(filedst);
freemem(src);
freemem(dst);
end;




使用一个30M的文件测试了一下,用时不到0.1秒。

蓝色光芒 2011-07-06
  • 打赏
  • 举报
回复
所有字符最后连接到一起还是单独?
cngst 2011-07-06
  • 打赏
  • 举报
回复
对了,再补充一点,因为楼主说文件非常大,所以我分块处理的,每块大小按3M定义的,可以根据实际情况再灵活调整。

如果文件不是超级大的话,不分块,一次性处理也可以。

再次强调,希望楼主多给分!
cngst 2011-07-06
  • 打赏
  • 举报
回复
根据楼主的描述,文件中应该都是宽字符,也就是说,连续的0也应该是成双出现的,文件长度也应该是2的位数,临时简单的写了个函数,应该可以满足楼主的要求了。

代码如下:


procedure TrimFileData(srcfile,dstfile:string);
const partlen=3072*1000;
var src,dst:pbyte;
filelen,lastpart,dstsize:dword;
filesrc,filedst:thandle;
i,partcnt:integer;

procedure ScanPart(param1:dword; var param2:dword); assembler;
asm
push esi
push edi
push ebx
mov esi,src
mov edi,dst
mov ecx,eax
xor ebx,ebx
@p1:
mov ax,word ptr[esi]
cmp ax,0
jz @p2
inc ebx
mov word ptr[edi],ax
add edi,2
@p2:
add esi,2
loop @p1
shl ebx,1
mov dword ptr[edx],ebx
pop ebx
pop edi
pop esi
end;

begin
filesrc:=fileopen(srcfile,fmopenread);
if fileexists(dstfile) then deletefile(dstfile);
filedst:=filecreate(dstfile);
filelen:=getfilesize(filesrc,nil);
partcnt:=filelen div partlen;
lastpart:=filelen mod partlen;
getmem(src,partlen);
getmem(dst,partlen);
for i := 0 to partcnt - 1 do
begin
fileread(filesrc,src^,partlen);
scanpart(partlen,dstsize);
filewrite(filedst,dst^,dstsize);
end;
if lastpart>0 then
begin
fileread(filesrc,src^,lastpart);
scanpart(lastpart,dstsize);
filewrite(filedst,dst^,dstsize);
end;
fileclose(filesrc);
fileclose(filedst);
end;




使用方法:TrimFileData('源文件','去除0后保存的新文件');

注意:函数没有检查文件长度是不是2的倍数。

如果没有问题的话,楼主应该多给我点分啊!
keeley20 2011-07-06
  • 打赏
  • 举报
回复
Sorry 我没表述清楚, 先谢谢各位的回复。



以这张图为例,我需要第一个 1 和最后一个4 之间的所有的数据



而这张图中 ,我需要的这是 N 和 ) 之间的数据。

这些数据经过WideCharToString 后就是一个字符串了。


蓝色光芒 2011-07-06
  • 打赏
  • 举报
回复
如果是单独一个0则保留,什么叫单独的0? 00 ,01 , 0A , A0 是不是只有第一种情况才处理?
楼主的问题没表达清楚哦
cngst 2011-07-06
  • 打赏
  • 举报
回复
文件有多大?连续的0完全去除,还是保留下一个0?

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧