【问题标题】:replaceing std::string with const char*用 const char* 替换 std::string
【发布时间】:2012-02-27 18:55:17
【问题描述】:

我想知道有人可以帮我实现这个方法,而我不需要使用 std::string。

该方法有两个参数,一个是char数组,另一个是char数组的大小。

传递的参数将是一个由逗号分隔的不同值的数组,例如"Rule1,Rule2,Rule3,Rule4,AT,T,Cat,Dog"。

成员变量“m_rulesSet”是一个包含模拟值的std::string。我想比较两者以检查“名称”是否在 std::string "m_ruleSet"

bool 
Matche(const char *str, size_t strSize)
{
    std::string target(str, strSize);

    if(m_ruleSet.empty())
    {
        return true;
    }
    if((NULL == str) || (strSize <= 0))
    {
        return false;
    }

    const char * ptr =0;
    const char * start = target.c_str();

    while ((ptr = strchr(start, ',')) != 0)
    {
        std::string name(start, ptr - start);
        if(name ==m_ruleSet)
        {
            return true;
        }
        start = ptr + 1;
    }
    if(*start)
    {
        std::string name(start);
        if(name==m_ruleSet)
        {
            return true;
        }
    }
    return false;
}

任何帮助将不胜感激,在此先感谢您

【问题讨论】:

  • 这个方法应该做什么?你哪里有问题?
  • 其实应该正好相反。你应该想要使用std::string而不是C字符串。
  • @netcoder:显然,std::string 并不总是最好的选择。特别是如果此功能是应用程序的瓶颈之一。
  • 如果他想定位一个使用 STL 不实用的平台怎么办? (例如 Android 直到最近)
  • 根据我的经验,使用 STL 字符串导致的大多数性能问题都来自于错误地使用 STL 字符串。就像,据我所见,在上面的代码中。

标签: c++


【解决方案1】:

看起来您只是使用std::string 来保存子字符串,然后进行比较。为了进行子字符串比较而复制是低效的。

代替

std::string name(start, ptr - start);
if(name ==m_ruleSet)

你可以写

if (ptr - start == m_ruleSet.size() && 0 == strncmp(start, m_ruleSet.c_str(), ptr-start))

您还应该使用memchr 并传入strstrSize,而不是将target 设为std::string

我的总体建议是使用适当的词法分析器/语法识别器,例如 flex+bison。这将比单独调用strchrstrncmp 更快地生成优化的DFA。如果您有多个要匹配的字符串(规则),这尤其有价值。


但这是一个简单的 DFA:

bool csv_match( const char * const haystack, size_t const haystack_size, const char* const needle, size_t const needle_size )
{
    const char * const haystack_end = haystack + haystack_size;
    int state = 0;
    // invariant: state == -1 if the current field doesn't match
    //            otherwise the first (state) characters have been matched
    for( const char* p = haystack; p < haystack_end; ++p ) {
        if (*p == ',') {
            if (state == needle_size) return true;
            state = 0;
        }
        else if (state < 0)
            ;
        else if (state >= needle_size || *p != needle[state])
            state = -1;
        else
            ++state;
    }
    return (state == needle_size);
}

像这样使用它

bool Matche(const char *str, size_t strSize) const { return csv_match(std, strSize, m_ruleSet.data(), m_ruleSet.size()); }

【讨论】:

  • 太棒了!你能解释一下这将如何在 memchr 中实现吗?
  • @aliaserror: strchr 需要一个以 NUL 结尾的字符串。 memchr 使用计数字符串。查看memchr 的帮助页面,应该很清楚strchr 的变化。
  • 您也可以使用一个无需复制即可处理子字符串的类,在我看来,它的使用变得更加直观和可读。例如来自 llvm 的This one
【解决方案2】:

所以你的意思是用strcmpstrncmp 替换std::string 比较(因为这是你唯一使用std::string 的东西,其他所有东西都已经在使用C 字符串)?好吧,如果你真的想要它:

bool Matche(const char *str, size_t strSize)
{
    if(m_ruleSet.empty())
        return true;
    if(!str || !strSize)     //remember that size_t is unsigned by standard
        return false;

    const char * ptr, start = str;
    while (ptr = memchr(start, ',', strSize))
    {
        size_t len = ptr - start;
        if(len == m_ruleSet.size() && !strncmp(start, m_ruleSet.c_str(), len))
            return true;
        strSize -= len + 1;
        start = ptr + 1;
    }
    return *start ? (strSize == m_ruleSet.size() && 
                     !strncmp(start, m_ruleSet.c_str(), strSize)) : false;
}

就像 Ben 在他的评论和回答中指出的那样,当您有一个额外的大小参数并且您的字符串不一定以零结尾时,您需要使用 memchr 而不是 strchr

您可能还想用 C 字符串替换 m_ruleSet(以摆脱 .c_str()),但我实际上首先质疑在 C++ 代码中是否需要用 C 字符串替换 std::string .

【讨论】:

  • @ChristianRau:您可能会从我的回答中得到一些提示。 strnchr 拼写为 memchr
  • 我们仍在使用 std::string m_ruleSet。 strcmp(start, m_ruleSet.c_str())m_ruleSet == start 好多少?
  • @BoPersson 我不知道直接将std::string 与 C 字符串进行比较会导致重载,我认为这会将 C 字符串转换为 std::string(OP想要阻止)。
  • 您刚刚使最后一列使用前缀匹配而不是完全匹配。这个问题看似很难。
  • @BenVoigt 我吓坏了!我要我该死的std::string 回来!
【解决方案3】:

string.h/cstring 提供了大多数字符串/基本内存操作的方法。您应该能够在其中找到几乎所有 std::string 方法的替代品。当你没有找到一个直接映射时,你可以使用cstring中的方法自己编写一个。查看您发布的代码,肯定需要strcpystrncpy(或memcpy)。

如果您有具体问题,请将其添加到帖子中,有人会帮助您。

【讨论】:

  • 在我看来不需要任何复制。字符串的所有使用都是只读的。
  • @BenVoigt 我的意思是创建nametarget。当然也可以优化,但是一对一的替换一次就可以用...
【解决方案4】:

你的意思是喜欢重写

std::string name(start);
if(name==m_ruleSet)
{
    return true;
}
return false;

进入

return m_ruleSet == start;

没有必要构造一个std::string 只是为了将它与一个C 字符串进行比较。 std::string 的 == 运算符无论如何都可以正常工作。

如果您需要将 m_ruleSet 与另一个 std::string 的子字符串或 C 字符串进行比较,有几个 std::string::compare 的重载可以做到这一点。

【讨论】:

  • 抱歉,我不完全理解 - 使用“开始”仍然需要我使用 std::string(str,strLength)?
  • std::string name(start); 将计算start 指向的字符串的长度。 m_ruleSet == start也一样,所以没必要单独做。
  • @Bo:但是基于签名,以及 strSize 被传递给构造函数的事实,输入被计数而不是 NUL 终止。当然,如果不是 NUL 终止的,一些原始代码将无法工作,那么谁能确定呢?
【解决方案5】:

所以你从 std::string 使用的方法是

  • 字符 * 符

std::string target(str, strSize); => char * target = strdup(str) 或 strcpy

  • .empty()

m_ruleSet.empty() => strlen(m_ruleSet.c_str())==0

  • 比较

name==m_ruleSet => strcmp(name.c_str(),m_ruleSet.c_str()) == 0

【讨论】:

  • 在功能方面没有从 char * 到 string 的一对一映射。除非有充分的理由你不需要混合 char* 和 std::string。我的问题是不知道哪些函数可用于操作 char *。 c风格字符串和std::string的使用方式完全不同。
  • 这并没有改变你的建议 #1 没用:他可以直接读取输入,不需要复制,#2 没用,你不需要测量一个字符串的长度来判断它是否为空,#3是错误的,因为它寻找一个终止NUL,而我们知道实际输入可能有逗号。除非你先做一个无用的副本,否则为了有一个 NUL。
  • 1.如果您将 char * 和长度传递给 std:: string 它会复制该字符串。同样的事情 2. strlen == 0 与查看字符串是否为空相同,除非您想在功能上添加其他功能,例如忽略空格 3.string1 == string2 is strcmp(str1,str2) == 0 。您提供了编辑和更改代码的方法我只是展示了如何实现与 std 字符串函数相同的功能
  • 这就是为什么代码是问题太慢了。使用 string.h 复制行为不会加快速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-23
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
相关资源
最近更新 更多