The opposite of str.find('X') -
What is the most efficient way of finding first character in std::string that is different than specific char? If I have a string that consists of mainly X'es, but at some point there is another char - how do I find it quickly?
std::string str = "XXXXXXXXXXXXXXX.XXXXXXXXXXX";
size_t index = str.find_first_not_of('X');
But a plain old for loop will be just as good.
Or, if you want an iterator instead of an index, perhaps like this:
std::string::iterator = std::find_if(str.begin(), str.end(),
[](char c){ return c != 'X'; });
I think the most efficient way would be to iterate through the string and compare each character with 'X', returning the first one that is different.
Without any prior knowledge about the string, I don't see an approach better than O(n), and calling find('X') succesively might be worse than just iterating through the characters.
Related
New to c++. I've searched but probably using wrong terms.
I want to find which slot in an array of many slots a few bytes long literal value is stored. Currently check each slot sequentially.
If I can use an internal function to scan the whole array as if it was one big string, I feel this would be much faster. (Old COBOL programmer).
Any way I can do this please?
I want to find which slot in an array of many slots a few bytes long literal value is stored. Currently check each slot sequentially.
OK, I'm going to take a punt and infer that:
you want to store string literals of any length in some kind of container.
the container must be mutable (i.e. you can add literals at will)
there will not be duplicates in the container.
you want to know whether a string literal as been stored in the container previously, and what "position" it was at so that you can remove it if necessary.
the string literals will be inserted in random lexicographical order and need not be sorted.
The container that springs to mind is the std::unordered_set
#include <unordered_set>
std::unordered_set<std::string> tokens;
int main()
{
tokens.emplace("foo");
tokens.emplace("bar");
auto it = tokens.find("baz");
assert(it == tokens.end()); // not found
it = tokens.find("bar"); // will be found
assert(it != tokens.end());
tokens.erase(it); // remove the token
}
The search time complexity of this container is O(1).
As you already found out by the comments, "scanning as one big string" is not the way to go in C++.
Typical in C++ when using C-style arrays and normally fast enough for linear search is
auto myStr = "result";
auto it = std::find_if(std::begin(arr), std::end(arr),
[myStr](const char* const str) { return std::strcmp(mystr,str) == 0; });
Remember that string compare function stop at the first wrong character.
More C++ style:
std::vector<std::string> vec = { "res1", "res2", "res3" };
std::string myStr = "res2";
auto it = std::find(vec.begin(), vec.end(), myStr);
If you are interested in very fast lookup for a large container, std::unordered_set is the way to go, but the "slot" has lost its meaning then, but maybe in that case std::unordered_map can be used.
std::unordered_set<std::string> s= { "res1", "res2", "res3" };
std::string myStr = "res2";
auto it = s.find(myStr);
All code is written as example, not compiled/tested
For a little something I was trying out in C++, I have accepted a string (say 'a tomato is red') and gotten rid of spaces ('atomatoisred').
Now how would I go about deleting recurring characters only, on condition that the first instance of that character gets to stay (so our example becomes,'atomisred')?
Thanks in advance!
You can use the erase-remove idiom in conjunction with a set keeping track of the duplicate characters:
std::set<char> dupes;
str.erase(
std::remove_if(
str.begin(), str.end(),
[&](char c) { return not dupes.insert(c).second; }),
str.end());
This also uses the fact that the return value of std::set::insert is a pair whose second element is a bool indicating whether the insertion took place.
If you want to implement it yourself (without stl), there are a number of ways.
Through sorting. This works if you don't care about the order of the chars. Sort your string first, then go through it, performing a very simple check on every element:
if( currentElement == elemebtBeforeIt )
deleteCurrentElement
Another way is to have an array dedicated to the unique characters (well, maybe not an array, but you'll get the idea). Go through your string, and for each charcter, check:
foreach Element of the string:
if( arrayOfUniqueElements contains currentElement )
do nothing
else
put currentElement into the arrayOfUniquElements
After this, you will have all unique elements in the dedicated array.
What is the best and most effective way to extract a string from a string? I will need this operation to be preforms thousands of times.
I have this string and I'd like to extract the URL. The URL is always after the "url=" substring until the end of the string. For example:
http://foo.com/fooimage.php?d=AQA4GxxxpcDPnw&w=130&h=130&url=http00253A00252F00252Fi1.img.com00252Fvi00252FpV4Taseyww00252Fhslt.jpg
and I need to extract the
http00253A00252F00252Fi1.img.com00252Fvi00252FpV4Taseyww00252Fhslt.jpg
I want to avoid using split and such.
If you absolutely need the results as a string, you'll have to measure,
but I doubt that anything will be significantly faster than the most
intuitive:
std::string
getTrailer( std::string const& original, std::string const& key )
{
std::string::const_iterator pivot
= std::search( original.begin(), original.end(), key.begin(), key.end() );
return pivot == original.end()
? std::string() // or some error condition...
: std::string( pivot + key.size(), original.end() );
}
However, the fastest way is probably not to extract the string at all,
but to simply keep it as a pair of iterators. If you need this a lot,
it might be worth defining a Substring class which encapsulates this.
(I've found a mutable variant of this to be very effective when
parsing.) If you go this way, don't forget that the iterators will
become invalid if the original string disappears; be sure to convert
anything you want to keep into a string before this occurs.
std::string inStr;
//this step is necessary
size_t pos = inStr.find("url=");
if(pos != std::string::npos){
char const * url = &inStr[pos + 4];
// it is fine to do any read only operations with url
// if you would apply some modifications to url, please make a copy string
}
you can use std::string::find() :
if its a char* than just move the pointer to the position right after "url="
yourstring = (yourstring + yourstring.find("url=")+4 );
I cant think of anything faster..
You could also look into the boost libraries.
For example boost::split()
I don't know how they actually perform in terms of speed, but it's definitely worth a try.
Basically I want to check a string array to see if any of the words match "and".
Is this possible?
Can you push me in the right direction?
Thanks
I should make it clear that the words are char put together best way to explain is an example
abc defg hijk and lmnop <-- each character is in its own element
I recommend you use std::string and not null-terminated char* strings (maybe you already are -- hard to be sure). And use a standard container rather than an array. Then use std::find (which would work on an array too, but containers are better).
Iterate through the array and use int string::compare ( const string& str ) const; to check for matches.
Break from the loop on first match.
I am guessing you'd like to take care of lower\upper casing and the word appearing in the beginning\end of the string.
std::string data;
std::transform(data.begin(), data.end(), data.begin(), ::tolower);
data.append(' ');
if (data.find("and ") != std::string::npos) ......
After programming a little in C I decided to jump right into C++. At first I was pleased with the presence of the string class and being able to treat strings as whole units instead of arrays of characters. But I soon found that the C-style strings had the advantage of letting the program move through it character by character, using pointer arithmetic, and carry out a desired logical operation.
I have now found myself in a situation that requires this but the compiler tells me it is unable to convert from type string to the C-style strings. So I was wondering, is there a way to use pointer arithmetic to reference single characters or to pass arguments to a function as the address of the first character while still using the string class without having to create arrays of characters or do I just want to have my cake and eat it too?
string characters can be accessed by index, pointers, and through the use of iterators.
if you wanted to use iterators, you could make a function that checks whether a string has a space in it or not:
bool spacecheck(const string& s)
{
string::const_iterator iter = s.begin();
while(iter != s.end()){
if (isspace(*iter))
return true;
else
++iter;
}
}
At the beginning of the function, I initialized an iterator to the beginning of the string s by using the .begin() function, which in this case returns an iterator to the first character in a string. In the while function, the condition is that iter != s.end(). In this case end() returns in iterator referring to the element after the last character of the string. In the body, (*iter), which is the value pointed to by iter, is sent to the function isspace(), which checks if a character is a space. If it fails, iter is incremented, which makes iter point to the next element of the string.
I am learning c++ myself and by writing all of this stuff out it has helped my own understanding some. I hope I did not offend you if this all seemed very simple to you, I was just trying to be concise.
I am currently learning from Accelerated c++ and I could not recommend it highly enough!
You can use &your_string[0] to get a pointer to the initial character in the string. You can also use your_string.begin() to get an iterator into the string that you can treat almost like a pointer (dereference it, do arithmetic on it, etc.)
You might be better off telling us more about what you're trying to accomplish though. Chances are pretty good that there's a better way to do it than with a pointer.
Edit: For something like counting the number of vowels in a string, you almost certainly want to use an algorithm -- in this case, std::count_if is probably the most suitable:
struct is_vowel {
bool operator()(char ch) {
static const char vowels[] = "aeiouAEIOU";
return strchr(vowels, ch) != NULL;
}
};
int vowels = std::count_if(my_string.begin(), my_string.end(), is_vowel());
We're still using begin(), but not doing any pointer(-like) arithmetic on it.