我的函数从文本文件中解析段 使用开始和结束字符串(参见main()) 并将段保存在单独的文件中。
我不知道它有什么问题,但它会返回这3个段文件:
1 START_TEXT_END
2 _START_BLABLUB_END
3开始4结束
输入test.txt(4个START ... END段):
_START_TEXT_END_START_BLABLUB_END_
_START_THIRD_END START 4 END
应该包含“START”和“END”,但缺少第3段(“START_THIRD_END”) 并且2.段错误地包括“_”。对于其他输入文件,它也会返回不准确的结果。 有什么想法吗?
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
long split(char *filename, char *segment_filename, char *str_start, char *str_end, long n_start, long n_end) {
long segments = 0, size_segment = 0;
FILE *file = fopen(filename, "rb"), *segmentfile;
long size_str_start = strlen(str_start);
long size_str_end = strlen(str_end);
long pos_str_start = 0;
long pos_str_end = 0;
int chr;
char *segment_filename_numbered;
char *segment = (char*)malloc(1);
fseek(file,0,0);
if (file) {
while ( (chr = fgetc(file)) != EOF && !feof(file) && !ferror(file)) {
size_segment++;
// scan for start string
if ( chr == str_start[pos_str_start] ) { pos_str_start++; }
else pos_str_start = 0;
if ( pos_str_start == size_str_start )
size_segment = size_str_start, pos_str_start = 0;
// scan for end string
if ( chr == str_end[pos_str_end] ) pos_str_end++;
else pos_str_end = 0;
if ( pos_str_end == size_str_end )
{
pos_str_end = 0;
segments++;
if (segments > n_start) {
segment = (char*) realloc(segment, size_segment);
//segment_filename_numbered = chars_cat2( segment_filename, chars_number(segments, '0', 8, 16) ); // SOME OF MY LIBRARY FUNCTIONS
segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10);
fseek(file, -size_segment, SEEK_CUR);
fread(segment, size_segment, 1, file);
segmentfile = fopen(segment_filename_numbered, "wb");
fwrite(segment, size_segment, 1, segmentfile);
fseek(file, size_segment, SEEK_CUR);
fclose(segmentfile);
}
}
}
fclose(file);
}
return segments;
}
int main(int argc, char* argv[])
{
split("test.txt", "test_", "START", "END", 0, 0);
system("Pause");
return 0;
}
我是新来的,手动在每行前面添加4个空格是一场噩梦,标记代码的简单方法是什么?
答案 0 :(得分:1)
可能还有其他问题,但有一个确定错误就是来电:
segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10);
segment_filename_numbered 被定义为指针,但需要是一个足够大的缓冲区来保存数字段的字符串表示
char segment_filename_numbered[16];
ltoa(segments, segment_filename_numbered, 10);
我以前没见过ltoa。我通常会使用snprintf,它允许您声明缓冲区大小以避免溢出。
修改
没有任何冒犯意味着,但是你正试图试图调试这个程序。我的建议是你调查标准库字符串函数(strstr,strchr等)并重写程序,一次读取多个char。该程序是否有一个应用程序 - 换句话说它是在某个地方/由某人使用 - 还是一个练习?
答案 1 :(得分:1)
好的,这次我想到了。 问题是这一行:
fseek(file, size_segment, SEEK_CUR);
不需要,因为行“fread(segment,size_segment,1,file);”已经移动了size_segment字节的文件位置。事实上你在这里加倍了。这就是你跳过字符的原因(尝试在每次循环运行时打印chr的值,它会跳过字符)
答案 2 :(得分:0)
该行
while ( (chr = fgetc(file)) != EOF && !feof(file) ...
有点奇怪。一个测试或另一个测试就足够了,但没关系。
我希望你不介意,但我试着按照我写的风格组织程序,看看我是否能看到一个bug。它帮助我阅读了它,但我没有看到任何新的错误,只有William Morris的: - (
我想我可能会试图'fseek 0'来获取开始和结束的文件位置,即使它不那么有效。至少它可能有助于调试它? - )
它可能会帮助其他人遵循它。如果我犯了一个错误,那可能是一个不明显的领域。
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
long split(char *filename, char *segment_filename,
char *str_start, char *str_end,
long n_start, long n_end) {
long segments = 0, size_segment = 0;
FILE *file, *segmentfile;
long size_str_start = strlen(str_start);
long size_str_end = strlen(str_end);
long pos_str_start = 0;
long pos_str_end = 0;
int chr;
char *segment_filename_numbered;
char *segment = (char*)malloc(1);
// fseek(file,0,0);
enum {LOOKING_FOR_START, LOOKING_FOR_END, MATCHED_MARKERS }
state = LOOKING_FOR_START;
if ((file=fopen(filename, "rb")) == NULL) {
fprintf(stderr, "Error: can't open file %s\n", filename);
return 0;
}
while ( (chr = fgetc(file)) != EOF && !feof(file) && !ferror(file)) {
size_segment++;
switch (state) {
case LOOKING_FOR_START:
// scan for start string
if ( chr == str_start[pos_str_start] ) { pos_str_start++; }
else pos_str_start = 0;
if ( pos_str_start == size_str_start ) {
size_segment = size_str_start;
pos_str_start = 0;
state = LOOKING_FOR_END;
}
break;
case LOOKING_FOR_END:
// scan for end string
if ( chr == str_end[pos_str_end] ) pos_str_end++;
else pos_str_end = 0;
if ( pos_str_end == size_str_end )
{
pos_str_end = 0;
state = MATCHED_MARKERS;
}
break;
case MATCHED_MARKERS:
segments++;
if (segments > n_start) {
segment = (char*) realloc(segment, size_segment);
//segment_filename_numbered = chars_cat2( segment_filename, chars_number(segments, '0', 8, 16) ); // SOME OF MY LIBRARY FUNCTIONS
//*** Error: uninitialised segment_filename_numbered ***
segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10);
fseek(file, -size_segment, SEEK_CUR);
fread(segment, size_segment, 1, file);
segmentfile = fopen(segment_filename_numbered, "wb");
fwrite(segment, size_segment, 1, segmentfile);
fseek(file, size_segment, SEEK_CUR);
fclose(segmentfile);
}
state = LOOKING_FOR_START;
default:
fprintf(stderr, "Fatal Error: state has become corrupt, value is %d\n", state);
break;
}
}
fclose(file);
return segments;
}
int main(int argc, char* argv[])
{
split("test.txt", "test_", "START", "END", 0, 0);
system("Pause");
return 0;
}
答案 3 :(得分:0)
我认为您的问题在于寻找分隔符之间的数据:
fseek(file,-size_segment,SEEK_CUR);
问题是你回到“size_segment”字节,但你已经阅读了更多:size_segment + size_str_end(段结尾)。 你应该写:
fseek(file, -size_segment - size_str_end,SEEK_CUR);
现在,以这种方式处理数据似乎不是很有效(读取数据,找到结尾,寻找数据,写入文件,然后寻找到先前的位置)。 为什么不在输出文件中读取数据时立即写入数据,并在遇到结束文本时更改输出文件?
如果您首先在循环中搜索开始文本,然后搜索数据(您将其写入文件),同时期望结束文本,那么它会更清晰。在这里,你同时拥有所有东西,很难跟上。