#c #string #stl
#c #строка #stl
Вопрос:
Если вы хотите узнать, начинается ли строка с другой, как бы вы это сделали в C / STL? В Java есть String.startsWith
, в Python тоже есть string.startwith
, в STL нет прямого метода для этого. Вместо этого есть std::string::find
и std::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
, может быть, есть еще какие-то другие способы добиться того же. find
немного удобнее, чем compare
, но я видел больше людей, рекомендующих compare
это find
.
Но какой из них предпочтительнее? Есть ли разница в производительности? Зависит ли это от реализации (GCC, VC и т. Д.)?
Ответ №1:
Недостатком find
является то, что if str1
длинный, тогда он будет бессмысленно искать его по всему пути str2
. Я никогда не замечал, чтобы оптимизатор был достаточно умен, чтобы понять, что вам важно только, равен ли результат 0 или нет, и прекратить поиск после начала str1
.
Недостатком compare
является то, что вам нужно проверить, что str2.length()
это не больше str1.length()
(или перехватить результирующее исключение и обработать его как ложный результат).
К сожалению, самое близкое к тому, что вы хотите в стандартной библиотеке std::strncmp
(и, конечно, вам нужно использовать c_str()
с этим), отсюда и необходимость boost::starts_with
или ваш собственный эквивалент, который включает проверки границ.
Комментарии:
1. Хорошо, это имеет смысл. Поэтому, если я не знаю длину str1, было бы лучше использовать boost
starts_with
. В противном случае, если я знаю, что str1 всегда будет больше, но не намного больше, чем str2,find
иcompare
тоже будет в порядке. Верно?2. @craesh: да, если недостаток не влияет на вас, тогда либо
find
илиcompare
дает правильный ответ, либо все в порядке. Существует множество ситуаций, когда дополнительный проход по строке незначителен.3. @SteveJessop аналогично, существует множество ситуаций, когда c_str может потребоваться выполнить копирование или когда строка длинная, что делает проверку очень дорогостоящей
4. @Foo Bah: я на самом деле не просматривал ни один источник в последнее время, но я сомневаюсь, что существует много реализаций, в которых
c_str()
выполняется копирование — обычно они завершают строку строковыми данными на месте. Конечно, я бы не стал полагаться наc_str
то, чтобы не создавать копию, и это одна из причин разочарования, котораяstrncmp
является самой близкой в стандартной библиотеке. Но я не думаю, что это сделает проверку дорогостоящей на практике, просто теоретически может быть дорогостоящей.5. @SteveJessop другое предостережение при использовании семейства
C
string заключается в том, что вы не можете сравнивать строки с нулевыми символами. Хотя это педанты и может быть неуместно в данном случае.
Ответ №2:
boost имеет алгоритм starts_with
, который реализует его довольно эффективно: http://www.boost.org/doc/libs/1_41_0/doc/html/boost/algorithm/starts_with.html
Нет никаких требований относительно того, как реализации STL должны реализовывать поиск или сравнение, кроме стандартного материала (возвращаемые значения …), Поэтому это полностью зависит от реализации.
Комментарии:
1. Ах, этого я не знал! Но я думаю,
str1.find(str2) == 0
что все еще читается немного лучше, чемstarts_with(str1,str2)
. Может быть, это просто вопрос вкуса…2. @craesh в конце концов, человек, использующий вашу программу, не может заботиться о внешнем виде базового кода 🙂
3. @craesh: ну, это вопрос того, сколько вы готовы заплатить за хороший вкус 🙂
4. Конечно, мои клиенты никогда не будут платить мне за хороший код или хороший вкус 🙂 Но как только вы посмотрите на код, который вы написали год назад, вы захотите понять, что вы написали, просто взглянув на него. Вы не можете прокомментировать все, поэтому код должен быть подробным (не всегда возможно).
Ответ №3:
Поскольку find()
, возможно, придется искать по всему string
, несмотря ни на что, вы можете обернуть compare()
так, если хотите:
#include <iostream>
#include <string>
using namespace std;
bool starts_with(const stringamp; s1, const stringamp; s2) {
return s2.size() <= s1.size() amp;amp; s1.compare(0, s2.size(), s2) == 0;
}
int main() {
const string s("zipzambam");
cout << starts_with(s, "zip") << endl;
}
Комментарии:
1. Хорошо, но это будет точно так же, как при использовании
boost::algorithm::starts_with
. Так что это решение может быть запасным вариантом на случай, если вы не сможете получить доступ к Boost, верно?2. FWIW , когда
Y
это typebool
,return X ? Y : false;
эквивалентноreturn X amp;amp; Y;
, и последнее немного более лаконично. Итак,return s2.size() <= s1.size() amp;amp; s1.compare(0, s2.size(), s2) == 0;
3. @SteveJessop Действительно. Исправлено. Спасибо
Ответ №4:
find
возможно, придется искать совпадения по всей строке, даже если первый символ не совпадает, поэтому я бы предложил compare
, или, как упоминал @Foo Bah, вы могли бы использовать starts_with
алгоритм boost.
Ответ №5:
Вы можете попробовать std::mismatch
, единственная глупость в этом алгоритме заключается в том, что вы должны убедиться, что первый диапазон меньше или равен второму диапазону.