как удалить подстроку из строки с ++ - PullRequest
4 голосов
/ 28 июля 2011

У меня есть string s="home/dir/folder/name"

Я хочу разделить s на s1="home/dir/folder" и s2="name";

Я сделал:

char *token = strtok( const_cast<char*>(s.c_str() ), "/" );
std::string name;
std::vector<int> values;
while ( token != NULL )
{
    name=token;

    token = strtok( NULL, "/" );
}

сейчас s1=name.А как насчет s2?

Ответы [ 6 ]

7 голосов
/ 28 июля 2011

Я бы рекомендовал не использовать strtok.Взгляните на Boost Tokenizer (вот несколько примеров ).

В качестве альтернативы, просто чтобы найти позицию последнего '/', вы можете использовать std::string::rfind:

#include <string>
#include <iostream>

int main() {
  std::string s = "home/dir/folder/name";
  std::string::size_type p = s.rfind('/');
  if (p == std::string::npos) {
    std::cerr << "s contains no forward slashes" << std::endl;
  } else {
    std::string s1(s, 0, p);
    std::string s2(s, p + 1);
    std::cout << "s1=[" << s1 << "]" << std::endl;
    std::cout << "s2=[" << s2 << "]" << std::endl;
  }
  return 0;
}
4 голосов
/ 28 июля 2011

Если ваша цель только получить позицию последнего \ или / в вашем string, вы можете использовать string :: find_last_of , которая именно это и делает.

Оттуда вы можете использовать string :: substr или конструктор для std::string, который принимает итераторы для получения нужной части.

Просто убедитесь, что исходная строка содержитпо крайней мере, \ или /, или что вы правильно обрабатываете дело.

Вот функция, которая делает то, что вам нужно, и возвращает pair, содержащий две части пути.Если указанный путь не содержит символов \ или /, весь путь возвращается как второй элемент пары, а первый элемент остается пустым.Если путь заканчивается на / или \, второй член пуст.

using std::pair;
using std::string;

pair<string, string> extract_filename(const std::string& path)
{
  const string::size_type p = path.find_last_of("/\\");

  // No separator: a string like "filename" is assumed.
  if (p == string::npos)
    return pair<string, string>("", path);

  // Ends with a separator: a string like "my/path/" is assumed.
  if (p == path.size())
    return pair<string, string(path.substr(0, p), "");

  // A string like "my/path/filename" is assumed.
  return pair<string, string>(path.substr(0, p), path.substr(p + 1));
}

Конечно, вы могли бы также изменить эту функцию, чтобы она выдавала ошибку вместо изящного выхода, когда путь делаетне имеют ожидаемого формата.

1 голос
/ 28 июля 2011

Несколько моментов: во-первых, использование strtok - неопределенное поведение;в случае g ++ это может даже привести к очень странному поведению.Вы не можете изменить содержимое std::string позади строк и ожидать, что это сойдет с рук.(Необходимость const_cast должна была вас предупредить.)

Во-вторых, если вы собираетесь манипулировать именами файлов, я настоятельно рекомендую boost::filesystem.Он знает все о таких вещах, как разделители путей и тому подобное, а также тот факт, что последний компонент пути обычно является специальным (поскольку это может быть имя файла, а не каталог).

В-третьих, если этопросто один из, или по какой-то другой причине вы не можете или не хотите использовать Boost:

std::string::const_iterator pivot
    = std::find( s.rbegin(), s.rend(), '/' ).base();

даст вам итератор для первого символа после последнего '/', илидо первого символа в строке, если его нет.После этого просто использовать два конструктора итератора строки для получения двух компонентов:

std::string basename( pivot, s.end() );
std::string dirname( s.begin(), pivot == s.begin() ? pivot : pivot - 1 );

А если вам позже потребуется поддержка Windows, просто замените find на:

static std::string const dirSeparators( "\\/" );
std::string::const_iterator pivot
    = std::find_first_of( s.rbegin(), s.rend(),
                          dirSeparators.begin(), dirSeparators.end() );
1 голос
/ 28 июля 2011

Оформить разделить строку буста .

Пример:

string str1("hello abc-*-ABC-*-aBc goodbye");
typedef vector< iterator_range<string::iterator> > find_vector_type;
find_vector_type FindVec; // #1: Search for separators
ifind_all( FindVec, str1, "abc" ); // FindVec == { [abc],[ABC],[aBc] }
typedef vector< string > split_vector_type;
split_vector_type SplitVec; // #2: Search for tokens
split( SplitVec, str1, is_any_of("-*"), token_compress_on ); 
// SplitVec == { "hello abc","ABC","aBc goodbye" }
0 голосов
/ 28 июля 2011

Просто используйте строковые методы:

std::string  s="home/dir/folder/name"
std::string::size_type n = s.find_last_of("/");
std::string  s1 = s.substr(0,n);

if (n != std::string::npos) // increment past the '/' if we found it
{  ++n;
}
std::string  s2 = s.substr(n);

Два совета:

  • Не используйте strtok EVER
  • Если вы играете с путями файловой системы, посмотрите на boost :: filesystem
  • Если вы хотите играть в основном с токенизацией, используйте операторы потока
  • Или boost :: tokenizer
0 голосов
/ 28 июля 2011

Вы не можете использовать strtok на std::string.strtok изменит строку.Это нарушает c_str() контракт.

Выполнение const_cast<> является большим признаком ошибки.

...