检查一个字符串是否以另一个字符串开头:使用find还是compare?

14

如果你想知道一个字符串是否以另一个字符串开头,你会如何在C++ / STL中实现?在Java中有String.startsWith,Python也有string.startwith,STL没有直接的方法。相反,有std::string :: findstd::string :: compare方法。到目前为止,我使用了两种方法,主要取决于我的当前心情:

if ( str1.compare( 0, str2.length(), str2 ) == 0 )
    do_something();
if ( str1.find(str2) == 0 )
    do_something();
当然,你也可以这样做:str.substr(0,str2.length()) == str2,可能还有其他方式可以实现相同的功能。与compare相比,find更方便,但我看到更多的人推荐使用compare而不是find
但是哪种方法更受青睐?是否存在性能差异?是否取决于实现(GCC、VC++等)?
5个回答

15
find的缺点在于如果str1很长,那么它将毫无意义地搜索整个str1来查找str2。我从未注意到优化器足够聪明,以意识到您只关心结果是否为0,并在str1的起始位置之后停止搜索。 compare的缺点在于需要检查str2.length()是否不大于str1.length()(或捕获由此产生的异常并将其视为错误结果)。
令人失望的是,在标准库中最接近您想要的功能的东西是std::strncmp(当然您需要使用c_str()),因此需要boost::starts_with或自己编写相应的代码来包含边界检查。

еҘҪзҡ„пјҢиҝҷеҫҲжңүйҒ“зҗҶгҖӮжүҖд»ҘеҰӮжһңжҲ‘дёҚзҹҘйҒ“str1зҡ„й•ҝеәҰпјҢжңҖеҘҪдҪҝз”Ёboostзҡ„starts_withгҖӮеҗҰеҲҷпјҢеҰӮжһңжҲ‘зҹҘйҒ“str1жҖ»жҳҜжҜ”str2еӨ§пјҢдҪҶдёҚдјҡеӨӘеӨ§пјҢйӮЈд№Ҳfindе’Ңcompareд№ҹеҸҜд»ҘгҖӮеҜ№еҗ—пјҹ - craesh
@craesh:是的,如果这个缺点对你没有影响,那么find或者compare都可以给出正确的答案,所以两者都可以。在许多情况下,字符串额外遍历一次是可以忽略不计的。 - Steve Jessop
@Foo Bah:我最近没有深入研究过任何源代码,但我怀疑很少有实现会对 c_str() 进行复制 - 通常它们会在原地以空字符结尾字符串数据。当然,我不会依赖 c_str 不进行拷贝,这也是标准库中最接近的strncmp令人失望的原因之一。但我认为这不会在实践中使检查变得昂贵,只是从理论上来说可能会变得昂贵。 - Steve Jessop
我接受了你的答案,因为它是最详细的,尽管还有其他很好的答案(对不起,大家!)。谢谢! - craesh
然而在我的测试中,似乎只有当指定的起始位置超出str1的末尾时,compare()才会抛出异常。当str2比str1长时,似乎没有抛出任何异常。 - John Fitzpatrick
显示剩余3条评论

9

如果需要,您可以像这样包装compare()

由于find()可能不管怎么样都必须搜索整个string,因此您可以这样做:

#include <iostream>
#include <string>
using namespace std;

bool starts_with(const string& s1, const string& s2) {
    return s2.size() <= s1.size() && s1.compare(0, s2.size(), s2) == 0;
}

int main() {
    const string s("zipzambam");
    cout << starts_with(s, "zip") << endl;
}

好的,但这将与使用boost::algorithm::starts_with完全相同。因此,如果您无法访问Boost,则此解决方案可能是一种后备选择,对吗? - craesh
1
就算参考价值不高,但当 Y 的类型是 bool 时, return X ? Y : false;return X && Y;是等价的,后者略微更加简洁。所以,return s2.size() <= s1.size() && s1.compare(0, s2.size(), s2) == 0; - Steve Jessop
@SteveJessop 确实。已修复。谢谢。 - Shadow2531

9

啊,不知道这个!但我认为 str1.find(str2) == 0starts_with(str1,str2) 更好读一些。也许这只是品味问题... - craesh
@craesh 最后,使用您的程序的人可能不关心底层代码的外观 :) - Foo Bah
@craesh:这取决于你愿意为好品味付出多少钱 :-) - Steve Jessop
当然,我的客户永远不会为漂亮的代码或良好的品味付费 :) 但是一旦你看着一年前写的代码,你希望通过简单地查看就能理解自己写的内容。你不能对所有东西都进行注释,因此代码应该详细(并非总是可能的)。 - craesh

2

find 可能需要搜索整个字符串以查找匹配项,即使第一个字符不匹配,因此我建议使用 compare,或者像 @Foo Bah 提到的那样,您可以使用 boost 的 starts_with 算法。


1
你可以尝试使用std::mismatch,这个算法唯一的“蠢”之处在于你必须确保第一个范围小于或等于第二个范围。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接