如何在不复制的情况下标记文件中的c样式字符串
How can I tokenize a c-style string from a file without making a copy?
假设我有一个常量c样式字符串,比如
const char* msg = "fred,jim,345,7665";
我想对此进行标记并读出各个字段,但出于性能原因,我不想复制。我该怎么做?
显然,strtok采用了一个非常量指针,boost::tokenizer是一个选项,但我不确定幕后在做什么。
不可避免地,您将需要字符串的一些副本,即使它是正在复制的子字符串。
如果你有一个strtok_r函数,你可以使用它,但它仍然需要一个可变的字符串来完成它的工作。然而,请注意,并不是所有系统都提供该功能(例如Windows),这就是我在这里提供实现的原因。它需要一个额外的参数:一个指向C字符串的指针来保存下一个匹配的地址。这使得它在理论上更具可重入性(线程安全)。但是,您仍将更改该值。如果愿意,您可以修改它以满足您的需要,也许可以将N个字节复制到目标缓冲区中,并以null终止该缓冲区以避免修改源字符串。
/*
Usage:
char *tok;
char *savep;
tok = mystrtok_r (somestr, ",", &savep);
while (NULL != tok)
{
/* Do something with `tok'. */
tok = mystrtok_r (NULL, ",", &savep);
}
*/
char *
mystrtok_r (char *str, const char *delims, char **nextp)
{
if (str == NULL)
str = *nextp;
str += strspn (str, delims);
*nextp = str + strcspn (str, delims);
**nextp = 0;
if (*str == 0)
return NULL;
++*nextp;
return str;
}
这取决于您将如何使用它。如果你想获得下一个令牌,然后是下一个(就像对字符串的迭代一样),那么你只需要将当前令牌复制到内存中
long strtok2( char *strDest, const char *strSrc, const char cTok, long lOffset, long lMax)
{
if(lMax > 0)
{
strSrc += lOffset;
char * start = strDest;
while(--lMax && *strSrc != cTok && (*strDest++ = * strSrc++) );
*strDest = 0; //for when the token was found, not the null.
return strDest - start - 1; //the length of the token
}
return 0;
}
我从http://vijayinterviewquestions.blogspot.com.au/2007/07/implement-strcpy-function.html
const char* msg = "fred,jim,345,7665";
char * buffer[20];
long offset = 0;
while(length = strtok2(buffer, msg, ',', offset, 20))
{
cout << buffer;
offset += (length+1);
}
好吧,如果没有更多的细节,很难确切地知道你想要什么。我猜您正在解析分隔符项,其中连续的分隔符应被视为零长度标记(这通常适用于逗号分隔的元素)。我还假设一个空行算作一个零长度的标记。这就是我的做法:
const char *token_begin = msg;
int length;
for(;;)
{
length = 0;
while(!isDelimiter(token_begin[length])) //< must include as delimiter
++length;
//..do something here with token. token is at: token_begin[0..length)
if ( token_begin[length] != 0 )
token_begin = &token_begin[length+1]; //skip beyond non-null delimiter
else
break; //token null terminated. exit
}
如果您要将令牌存储在某个地方,那么在任何情况下都需要一个副本,strtok
通过使用字符串(其中放置null
终止字符)很好地做到了这一点。
我看到的唯一一个避免复制它的选项是lexer,它读取字符串,并通过状态机通过扫描字符串并将部分结果存储在缓冲区中来生成令牌,但在任何情况下,每个令牌都应该至少存储在以null结尾的字符串中,因为你并没有真正保存任何东西。
这是我的建议,我的代码是结构化的,并使用全局变量pos
(我知道全局变量是一种糟糕的做法,但这只是给你一个想法),如果你需要OOP,你可以用数据成员来替换它。
int position, messageLength;
char token[MAX]; // MAX = Value greater than the maximum length
// of the tokens(e.g. 1,000);
bool hasNext()
{
return position < messageLength;
}
char* next(const char* message)
{
int i = 0;
while (position < messageLength && message[position] != ',') {
token[i++] = message[position];
position++;
}
position++; // ',' found
token[i] = ' ';
return token;
}
int main(int argc, char **argv)
{
const char* msg = "fred,jim,345,7665";
position = 0;
messageLength = strlen(msg);
while (hasNext())
cout << next(msg) << endl;
return EXIT_SUCCESS;
}
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 有没有办法从非C/C++文件中读取C++原始字符串文字的内容
- 如何打开并写入一个名称取自C++中字符串的文件
- 如何从二进制文件中读取字符串
- 如何在 c++ 中使用 getline 从文件中读取字符串?
- 将字符串与文件上的数据进行比较
- 用户输入字符串的文件附加问题..C++
- 如何从文件中读取两个字符串和数字数组,并将它们存储在对象向量中
- 如何使字符串出现在编译的二进制可执行文件的开头?
- 使用文件内容作为硬编码字符串
- 将文件复制到自定义位置,存在字符串转换问题
- 在 c++ 中连接字符串和整数,以便在 C++ 11 不支持计算机的情况下读取多个文件
- 声明要在 qml 和 cpp 文件中使用的全局字符串
- C 通过char读取文件字符串的文件char;崩溃
- 我不明白如何将 toupper 和 isalpha 与.txt文件字符串输入一起使用
- 在 CPP 文件中使用 make 文件字符串变量
- 编译 PyGAMMA Mac Lion:g++ 找不到标准的 C++ 头文件(字符串/iostream..)
- 如何在c++中使用文件字符串作为命令
- 使用 TinyXML 解析 XML 文件字符串
- 递归下降解析器帮助(不读取文本文件字符串)