开发者

how to remove substring from string c++

开发者 https://www.devze.com 2023-03-23 08:51 出处:网络
I have a string s=\"home/dir/folder/name\" I want to split s in s1=\"home/dir/folder\" and s2=\"name\";

I have a string s="home/dir/folder/name"

I want to split s in s1="home/dir/folder" and s2="name";

I did:

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

    token = strtok( NULL, "/"开发者_如何学运维 );
}

now s1=name. What about s2?


I'd recommend against using strtok. Take a look at Boost Tokenizer instead (here are some examples).

Alternatively, to simply find the position of the last '/', you could use 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;
}


If your goal is only to get the position of the last \ or / in your string, you might use string::find_last_of which does exactly that.

From there, you can use string::substr or the constructor for std::string that takes iterators to get the sub-part you want.

Just make sure the original string contains at least a \ or /, or that you handle the case properly.

Here is a function that does what you need and returns a pair containing the two parts of the path. If the specified path does not contain any \ or / characters, the whole path is returned as a second member of the pair and the first member is empty. If the path ends with a / or \, the second member is empty.

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));
}

Of course you might as well modify this function to throw an error instead of gracefully exiting when the path does not have the expected format.


Several points: first, your use of strtok is undefined behavior; in the case of g++, it could even lead to some very strange behavior. You cannot modify the contents of an std::string behind the strings back and expect to get away with it. (The necessity of a const_cast should have tipped you off.)

Secondly, if you're going to be manipulating filenames, I'd strongly recommend boost::filesystem. It knows all about things like path separators and the like, and the fact that the last component of a path is generally special (since it may be a filename, and not a directory).

Thirdly, if this is just a one-of, or for some other reason you can't or don't want to use Boost:

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

will give you an iterator to the first character after the last '/', or to the first character in the string if there isn't one. After that, it's a simple to use the two iterator constructors of string to get the two components:

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

And if you later have to support Windows, just replace the find with:

static std::string const dirSeparators( "\\/" );
std::string::const_iterator pivot
    = std::find_first_of( s.rbegin(), s.rend(),
                          dirSeparators.begin(), dirSeparators.end() );


Check out boost string split.

Example:

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" }


You can't use strtok on std::string. strtok would modify the string. It break the c_str() contract.

Doing const_cast<> is a big sign for error.


Just use the string methods:

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);

Two bits of advice:

  • Don't use strtok EVER
  • If you are playing with file system paths look at boost::filesystem
  • If you want to play generally with tokenization use the stream operators
  • Or boost::tokenizer
0

精彩评论

暂无评论...
验证码 换一张
取 消