I want to know the positions of the "_" in a string:
string str("BLA_BLABLA_BLA.txt");
Something like:
string::iterator it;
for ( it=str.begin() ; it < str.end(); it++ ){
if (*it == "_") //this goes wrong: pointer and integer comparison
{
pos(1) = it;
}
cout << *it << endl;
}
Thanks,
André
Note that "_" is a string literal, while '_' is a character literal.
If you dereference an iterator into a string, what you get is a character. Of course, characters can only be compared to character literals, not to string literals.
However, as others have already noticed, you shouldn't implement such an algorithm yourself. It's been done a million times, two of which (std::string::find() and std::find()) ended up in C++' standard library. Use one of those.
std::find(str.begin(), str.end(), '_');
// ^Single quote!
string::find is your friend.
http://www.cplusplus.com/reference/string/string/find/
someString.find('_');
Why dont you use the find method : http://www.cplusplus.com/reference/string/string/find/
You can make use of the find function as:
string str = "BLA_BLABLA_BLA.txt";
size_t pos = -1;
while( (pos=str.find("_",pos+1)) != string::npos) {
cout<<"Found at position "<<pos<<endl;
}
Output:
Found at position 3
Found at position 10
Related
My string:
std::string With_esc = "asd\b";
I want to convert it to a simple string "as" (apply the backspace character and forget it).
Is there any way to do this in C++? It should look like this:
std::string With_esc = "asd\b";
std::string Without_esc = With_esc; //Here I should convert it
std::ofstream FWith_esc ("with");
std::ofstream FWithout_esc ("without");
FWithout_esc << Without_esc;
FWith_esc << With_esc;
Bash:
~ cat -e with
asd^H
~ cat -e without
as
Unfortunately I don't know how to convert it, so both files look exactly the same.
Assuming you're lucky enough to use C++11 (otherwise adapt this code to your favorite regex engine):
string With_esc = R"asd\b";
string Without_esc = regex_replace(With_esc, regex(".\\b"), "");
As pointed out in comments this approach has following limitations:
It'll replace only one "back" so if you have "12\b\b" you'll get "1\b". To handle this you need to loop until input and output (for regex_replace()) are different (or maybe a better regex, I'm not such good with them).
It won't handle \b as beginning of the string like in "\b123". To handle this you need a simple string replacement (using technique suggested by Giobunny) to remove \b after a regex_replace().
Note here I'm using verbatim strings (it's ok for an example if your text comes from a file but if you're working with string literals you need to update regex accordingly).
UPDATE
As noted by Eric Finn this expression will also match multiple backspaces then "a\b\b\b" will become "\b\b" and then "\", that's obviously wrong. As he suggested a better regex should include check for "[^\b]\b" too.
Try something like this, if you don't want to use a regex:
std::string convertBackspaces(std:string str)
{
std::string::iterator iter = str.begin();
std::string::iterator end = str.end();
while (iter != end)
{
iter = std::find(iter, end, '\b');
if (iter == end) break;
if (iter == str.begin())
iter = str.erase(iter);
else
iter = str.erase(iter-1, iter+1);
end = str.end();
}
return str;
}
std::string Without_esc = convertBackspaces(With_esc);
You can replace the substring "\b" with an empty string.
It's not the fastest/safest method but it will work,
you can follow.
Replace substring with another substring C++
I am trying to modify someone's code which uses this line:
out.write(&vecBuffer[0], x.length());
However, I want to modify the buffer beforehand so it removes any bad characters I don't want to be output. For example if the buffer is "Test%string" and I want to get rid of %, I want to change the buffer to "Test string" or "Teststring" whichever is easier.
std::replace will allow replacing one specific character with
another, e.g. '%' with ' '. Just call it normally:
std::replace( vecBuffer.begin(), vecBuffer.end(), '%', ' ' );
Replace the '%' with a predicate object, call replace_if,
and you can replace any character for which the predicate
object returns true. But always with the same character. For
more flexibility, there's std::transform, which you pass
a function which takes a char, and returns a char; it will
be called on each character in the buffer.
Alternatively, you can do something like:
vecBuffer.erase(
std::remove( vecBuffer.begin(), vecBuffer.end(), '%' ).
vecBuffer.end() );
To remove the characters. Here too, you can replace remove
with remove_if, and use a predicate, which may match many
different characters.
The simplest library you can use is probably the Boost String Algorithms library.
boost::replace_all(buffer, "%", "");
will replace all occurrences of % by nothing, in place. You could specify " " as a replacement, or even "REPLACEMENT", as suits you.
std::string str("Test string");
std::replace_if(str.begin(), str.end(), boost::is_any_of(" "), '');
std::cout << str << '\n';
You do not need to use the boost library. The easiest way is to replace the % character with a space, using std::replace() from the <algorithm> header:
std::replace(vecBuffer.begin(), vecBuffer.end(), '%', ' ');
I assume that vecBuffer, as its name implies, is an std::vector. If it's actually a plain array (or pointer), then you would do:
std::replace(vecBuffer, vecBuffer + SIZE_OF_BUFFER, '%', ' ');
SIZE_OF_BUFFER should be the size of the array (or the amount of characters in the array you want to process, if you don't want to convert the whole buffer.)
Assuming you have a function
bool goodChar( char c );
That returns true for characters you are approved of and false otherwise,
then how about
void fixBuf( char* buf, unsigned int len ) {
unsigned int co = 0;
for ( unsigned int cb = 0 ; cb < len ; cb++ ) {
if goodChar( buf[cb] ) {
buf[co] = buf[cb];
co++;
}
}
}
I want to remove the substring of my string , it looks something like this :
At(Robot,Room3)
or
SwitchOn(Room2)
or
SwitchOff(Room1)
How can I remove all the characters from the left bracket ( to the right bracket ) , when I don't know their indexes ?
If you know the string matches the pattern then you can do:
std::string str = "At(Robot,Room3)";
str.erase( str.begin() + str.find_first_of("("),
str.begin() + str.find_last_of(")"));
or if you want to be safer
auto begin = str.find_first_of("(");
auto end = str.find_last_of(")");
if (std::string::npos!=begin && std::string::npos!=end && begin <= end)
str.erase(begin, end-begin);
else
report error...
You can also use the standard library <regex>.
std::string str = "At(Robot,Room3)";
str = std::regex_replace(str, std::regex("([^(]*)\\([^)]*\\)(.*)"), "$1$2");
If your compiler and standard library is new enough, then you could use std::regex_replace.
Otherwise, you search for the first '(', do a reverse search for the last ')', and use std::string::erase to remove everything in between. Or if there can be nothing after the closing parenthesis then find the first and use std::string::substr to extract the string you want to keep.
If the trouble you have is actually finding the parentheses the use std::string::find and/or std::string::rfind.
You have to search for the first '(' then erase after until 'str.length() - 1' (assuming your second bracket is always at the end)
A simple and safe and efficient solution:
std::string str = "At(Robot,Room3)";
size_t const open = str.find('(');
assert(open != std::string::npos && "Could not find opening parenthesis");
size_t const close = std.find(')', open);
assert(open != std::string::npos && "Could not find closing parenthesis");
str.erase(str.begin() + open, str.begin() + close);
Never parse a character more than once, beware of ill-formed inputs.
small question about C++ replace function. I'm parsing every line of text input line by line. Example of the text file:
SF27_34KJ
EEE_30888
KPD324222
4230_333
And I need to remove all the underscores on every line and replace it with a comma. When I try something like this:
mystring.replace(mystring.begin(), mystring.end(), '_', ',');
on every line - instead of "SF27,34KJ" I get 95x "," char. What could be wrong?
Use std::replace():
std::replace(mystring.begin(), mystring.end(), '_', ',');
basic_string::replace doesn't do what you think it does.
basic_string::replace(it_a, it_e, ... ) replaces all of the characters between it_a and it_e with whatever you specify, not just those that match something.
There are a hundred ways to do what you're trying to do, but the simplest is probably to use the std::replace from <algorithm>, which does do what you want:
std::replace(mystring.begin(), mystring.end(), '_', ',');
Another method is to use std::transform in conjunction with a functor. This has an advantage over std::replace in that you can perform multiple substitutions in a single pass.
Here is a C++03 functor that would do it:
struct ReplChars
{
char operator()(char c) const
{
if( c == '_' )
return ',';
if( c == '*' )
return '.';
return c;
}
};
...and the use of it:
std::transform(mystring.begin(), mystring.end(), mystring.begin(), ReplChars());
In C++11, this can be reduced by using a lambda instead of the functor:
std::transform(mystring.begin(), mystring.end(), mystring.begin(), [](char c)->char
{
if( c == '_' )
return ',';
if( c == '*' )
return '.';
return c;
});
Looking here, there is no replace method which takes two iterators and then two characters. Considering the ascii value of '_' is 95, I'm guessing you're hitting this one instead:
string& replace ( iterator i1, iterator i2, size_t n2, char c );
So instead of replacing all instances of '_' with ',', instead you're replacing the string from begin() to end() with 95 ','s.
See here for how to replace occurrances in a string.
This isn't exactly how replace works. Check out the api http://www.cplusplus.com/reference/string/string/replace/, you give iterators for the beginning and end along with a string to copy in, but the other argument is the maximum length of that section.
To get the functionality that you're going for, try finding a substring and replacing it (two calls). That's detailed here: Replace part of a string with another string .
How would I look through a string for a word rather then each character in that word. I have my code here and it always seems to find everything that is .obj even if its o or b or j or "." I checked the docuementation here but was unable to find an answer. Here is my code:
string &str = *it;
if(it->find(".obj"))
{
cout << "Found .Obj" << endl;
}
I also tried to use string::compare but that failed.
find does search for the full text string that you pass as the function argument. What you're misunderstanding is the return value; find doesn't return true or false for whether or not it found the string you requested; it returns the index in the string where it found your requested substring, or std::string::npos if no match was found.
So for example:
std::string a = "foobar.obj";
std::string b = "baz.obj";
std::string c = "qux";
std::string d = ".obj";
a.find(".obj") == 6
b.find(".obj") == 3
c.find(".obj") == std::string::npos // not found
d.find(".obj") == 0
When interpreted as a boolean value, any integer other than 0 is treated as "true" -- even the "not found" std::string::npos value. Which is, I think, what has you confused.
So in your "if" statement, then, instead of:
if (it->find(".obj"))
You want to be testing:
if (it->find(".obj") != std::string::npos)