代码之家  ›  专栏  ›  技术社区  ›  David Sykes

为什么std::string.find(text,std::string:npos)不返回npos?

  •  3
  • David Sykes  · 技术社区  · 15 年前

    我在一个字符串中执行一系列搜索,在该行的某个位置,其中一个字符串将丢失,我的一组搜索将失败。

    我原以为一旦职位达到std::string::npos,它就会留在那里,但不会。将std::string::npos传递到std::string.find似乎再次开始搜索。

    std::string str("frederick");
    std::string::size_type pos = str.find("der",std::string::npos);
    TS_ASSERT_EQUALS(pos, std::string::npos); // FAIL, 3 is returned
    

    为什么不用它来表示字符串的结尾?

    更新: 其目的是按顺序搜索一系列字符串,并在最后检查结果。

    pos = str.find(string1, pos)
    pos = str.find(string2, pos)
    pos = str.find(string3, pos)
    if (pos != std:string::npos)
    { // All strings found
    
    7 回复  |  直到 10 年前
        1
  •  10
  •   CB Bailey    15 年前

    查看规范,我认为您的实现中可能有一个bug。

    basic_string::find 应返回最低位置 xpos 这样 pos <= xpos xpos + str.size() <= size() at(xpos + I) == str.at(I) 对于所有元素 I 被控制 str .

    basic_string::npos 是-1转换为无符号类型,因此必须是该无符号类型可表示的最大数字。鉴于没有其他职位 XPOS 甚至可以满足第一部分 npos & = XPOS find 必须返回 非营利组织 就我所见,失败时 非营利组织 是唯一有效的返回值 基本_字符串::查找 通过时 非营利组织 作为第二个参数。

        2
  •  4
  •   MSalters    15 年前

    比较字符串::find()和字符串::copy()。(在N2798中,这是21.3.7.2和21.3.6.7,第686/687页),两者都有立场论点。然而,只有string::copy有一个“requires:pos<=size()”子句。因此,字符串::find可以 需要pos<=size()。

    从那时起,查尔斯·贝利就有了正确的逻辑。看看有效返回值的范围,很明显只有字符串::npos才是与需求匹配的返回值。返回的任何其他值小于string::npos,失败21.3.7.2/1。


    N2798=08-0308,版权所有ISO/IEC:

    21.3.7.2 basic_string::find [string::find]

    size_type find(const basic_string<charT,traits,Allocator>& str, size_type pos = 0) const;

    1效果:确定最低位置 xpos 如果可能,使以下两种情况都能得到: 艾斯 pos <= xpos xpos + str.size() <= size(); 艾斯 traits::eq(at(xpos+I), str.at(I)) 对于所有元素 I 由控制的字符串 str . 2回报: XPOS 如果函数可以确定 XPOS . 否则,返回 npos . 3备注:用途 traits::eq() .

        3
  •  3
  •   James Hopkin    15 年前

    std::string::npos 不是的有效参数 std::string::find .

    定义 find 标准中只提到 npos 作为可能的返回值,不是起始位置。

        4
  •  3
  •   CB Bailey    15 年前

    您可能会发现,在这种情况下,自由函数std::search更容易使用。例如。

    std::string::const_iterator iter = str.begin();
    
    iter = std::search( iter, str.end(), string1.begin(), string1.end() );
    iter = std::search( iter, str.end(), string2.begin(), string2.end() );
    iter = std::search( iter, str.end(), string3.begin(), string3.end() );
    
        5
  •  1
  •   peterchen    10 年前

    如果通过,则未定义行为 npos :

    [更新]
    STL文档(无论如何,我能找到的两个复制品)提到 string::npos 仅尽可能返回值,而不是作为 pos . 后者是搜索开始的索引。

    但是也请看下面的评论(我不是ISO标准的专家,我根据我的文档限制了我的期望)。

    STL实现通常使用明显超出范围的值(例如( (size_type)-1) . 如何将其作为参数处理还没有明确说明,所以我不会依赖于这种行为。 [更新]

    所以你需要从0开始检查 pos != npos 每次呼叫后查找:

     pos = str.find(string1, 0)
     if (pos != std:string::npos)
       pos = str.find(string2, pos)
     if (pos != std:string::npos)
       pos = str.find(string3, pos)
    
     if (pos != std:string::npos)
     { 
       // All strings found
     }
    
        6
  •  0
  •   Paolo Tedesco    15 年前

    您应该使用字符串的长度作为起始位置。

        7
  •  0
  •   Idan K    15 年前

    将std::string::npos作为第二个要查找的参数传递意味着“在字符串中std::string::npos位置上或之后开始查找”。

    很明显这不是你想要的。

    编辑:

    这可能会实现您最初的预期:

    string s;
    string::size_type pos;
    
    if ((pos = s.find(s1)) != string::npos && (pos = s.find(s2, pos)) != npos && 
        (pos = s.find(s3,pos)) != string::npos)
    {
        // okay
    }
    

    我没有测试过它,但它应该可以工作,你可能更喜欢彼得森风格,因为它更可读。