Efficient way to check if string contains value of vector<string>? - c++

I'm pretty new to C++ programming but for certain reasons I need to develop a small tool in C++. I've written the same tool in C# already. Right now I'm trying to check if my string contains a value that is stored in a std::vector. In C# this is pretty straight forward, simply using something like this:
if(string.Contains(myarray)) { // do sth. }
In C++ this seems way harder to achieve. I googled quite a bit but so far I found only solutions to check if the WHOLE string exists in an array and not just a certain part of it.

Unfortunately std::string does not have a method that can see if a element of a vector is in a string like C# does. What it does have though is std::string::find which can determine if a string is contained within the string you call find on. You could use that like
std::vector<std::string> words;
// fill words
std::string search_me = "some text";
for (const auto & e : words)
{
if (search_me.find(e) != std::string::npos)
{
// e is contained in search me. do something here
// call break here if you only want to check for one existence
}
}
This is O(N*complexity_of_find).

Use a for loop and the find method.

I would suggest std::find_first_of
Not sure if I understood your exact problem, though. Could you give a small example of what your are trying to find in what?

If you need more effective way to find several substrings in string than straightforward find string-by-string, you can use Aho-Corasick algorithm
It uses trie to hold substrings. First google link to c++ implementation

Related

dealing with stringstream in C++

i am reverting back to cpp after long years i have not been using it at all. i am trying to stay up date whilst refreshing my memories with correct practices and syntax, so i prefer the answers to be leaned towards cpp 17 onward(though 20 is not out yet).
so my situation is like this, assuming i have a stringstream object, i want to find an efficient way to convert its contents into upper/lower case. then i'll play with it(each even char in the string, etc). however, as far as i remember, unlike other programming languages, in c++ ::toupper/lower is done on chars, so i think it means i need to use std::transform on this container.
if you could regard the following questions while answering it would be great and allow me to capture multiple birds with one net, or something like this:
is it possible to do this with a for_each?
is it possible to use string_view and then refer to it to do the operations on it if i don't want to create a new string object to do the case manipulation?
are there any iterators for stringstream object? (like begin(),end() etc)
so what's the best way to do implement case change here?
is it possible to do this somehow without converting this to string, but rather manipulating it manually or is it path for trouble?
here's what i tried and failed ungracefuly with:
int main() {
std::stringstream beginnersmistake;
beginnersmistake<<"learning"<< " " << "to"<< "program" <<'\n';
std::function<std::stringstream> ttoupper = [&beginnersmistake](){
std::string stemp = beginnersmistake.str();
std::transform(stemp.begin(),stemp.end(),stemp.begin(),::toupper);
};
std::cout<<"voila! a mistake comming:" << ttoupper;
beginnersmistake.clear();
getchar();
return 0;
}
thank you very much for helping a noobie joining the site :)

C# to C++ Conversion: Searching Arrays

I have a working (well, buildable, but WIP nonetheless) game that I coded in C# using XNA a while back, and I'm now converting the game to C++. In converting some of my methods, I'm encountering the error that I cannot really find anything equivalent to some of the Array methods, such as FindAll, Find, and Exists. I'm using vectors and any help on an equivalent method and how to implement it would be very helpful.
For example, in C# I had:
if (Array.Exists(tileList, tile => tile.Position.X == e.Position.X))
Where e was some entity, tileList was an array of all the tiles in the game, and tile was obviously the tile in the array.
How could I create something with a near-identical function in C++?
It looks like you probably want something like:
if (std::any_of(tileList.begin(), tileList.end(),
[](tile e) { return tile.position.X == e.Position.X; }))
// whatever
If you have an older compiler (std::any_of was added in C++11, so older compilers don't have it) you could use std::find or std::find_if instead. As you'd probably guess, these try to find the location of the matching element, not just tell you if one exists, so it'll be a little clumsier to use, but not drastically so (basically, you have to compare the returned position against tileList.end() to see whether you got a match or not).

Efficient way to truncate string to length N

For example, suppose I have std::string containing UNIX-style path to some file:
string path("/first/second/blah/myfile");
Suppose now I want to throw away file-related information and get path to 'blah' folder from this string. So is there an efficient (saying 'efficient' I mean 'without any copies') way of truncating this string so that it contains "/first/second/blah" only?
Thanks in advance.
If N is known, you can use
path.erase(N, std::string::npos);
If N is not known and you want to find it, you can use any of the search functions. In this case you 'll want to find the last slash, so you can use rfind or find_last_of:
path.erase(path.rfind('/'), std::string::npos);
path.erase(path.find_last_of('/'), std::string::npos);
There's even a variation of this based on iterators:
path.erase (path.begin() + path.rfind('/'), path.end());
That said, if you are going to be manipulating paths for a living it's better to use a library designed for this task, such as Boost Filesystem.
While the accepted answer for sure works, the most efficient way to throw away the end of a string is to call the resize method, in your case just:
path.resize(N);

C++, Multilanguage/Localisation support

what's the best way to add multilanguage support to a C++ program?
If possible, the language should be read in from a plain text file containing something like key-value pairs (§WelcomeMessage§ "Hello %s!").
I thought of something like adding a localizedString(key) function that returns the string of the loaded language file. Are there better or more efficient ways?
//half-pseudo code
//somewhere load the language key value pairs into langfile[]
string localizedString(key)
{
//do something else here with the string like parsing placeholders
return langfile[key];
}
cout << localizedString(§WelcomeMessage§);
Simplest way without external libraries:
// strings.h
enum
{
LANG_EN_EN,
LANG_EN_AU
};
enum
{
STRING_HELLO,
STRING_DO_SOMETHING,
STRING_GOODBYE
};
// strings.c
char* en_gb[] = {"Well, Hello","Please do something","Goodbye"};
char* en_au[] = {"Morning, Cobber","do somin'","See Ya"};
char** languages[MAX_LANGUAGES] = {en_gb,en_au};
This will give you what you want. Obviously you could read the strings from a file. I.e.
// en_au.lang
STRING_HELLO,"Morning, CObber"
STRING_DO_SOMETHING,"do somin'"
STRING_GOODBYE,"See Ya"
But you would need a list of string names to match to the string titles. i.e.
// parse_strings.c
struct PARSE_STRINGS
{
char* string_name;
int string_id;
}
PARSE_STRINGS[] = {{"STRING_HELLO",STRING_HELLO},
{"STRING_DO_SOMETHING",STRING_DO_SOMETHING},
{"STRING_GOODBYE",STRING_GOODBYE}};
The above should be slightly easier in C++ as you could use the enum classes toString() method (or what ever it as - can't be bothered to look it up).
All you then have to do is parse the language files.
I hope this helps.
PS: and to access the strings:
languages[current_language][STRING_HELLO]
PPS: apologies for the half c half C++ answer.
Space_C0wb0w's suggestion is a good one. We currently use successfully use ICU for that in our products.
Echoing your comment to his answer: It is indeed hard to say that ICU is "small, clean, uncomplicated". There is "accidental" complexity in ICU coming from its "Java-ish" interface, but a large part of the complexity and size simply comes from the complexity and size of the problem domain it is addressing.
If you don't need ICU's full power and are only interested in "message translation", you may want to look at GNU gettext which, depending on your platform and licencing requirements, may be a "smaller, cleaner and less-complicated" alternative.
The Boost.Locale project is also an interesting alternative. In fact, its "Messages Formatting" functionality is based on the gettext model.
Since you are asking for the best way (and didn't mention the platform) I would recommend GNU Gettext.
Arguably it is the most complete and mature internationalization library for C/C++ programming.

Write a program to count how many times each distinct word appears in its input

This is a question(3-3) in accelerated C++.
I am new to C++. I have thought about this for a long time, however, I can't figure it out.
Will anyone resolve this problem for me?
Please explain it in detail, you know I am not very good at programming. Tell me the meaning of the variables you use.
The best data structure for this is something like a std::map<std::string,unsigned>, but you don't encounter maps until chapter 7.
Here are some hints based on the contents of chapter 3:
You can put strings in a vector, so you can have std::vector<std::string>
Strings can be compared, so std::sort works with std::vector<std::string>, and you can check if two strings are the same with s1==s2 just like for integers.
You saw in chapter 1 that std::cin >> s reads a word from std::cin into s if s is a std::string.
To provide maximal learning experience, I will not provide pastable code. That's an exercise. You have to do it yourself to learn as much as you can.
This is the perfect scenario for employing a kind of map that creates its value type upon accessing a non-existing key. Fortunately, C++ has such a map in its standard library: std::map<key_type,value_type> is exactly what you need.
So here's the jigsaw pieces:
you can read word by word from a stream into a string by using operator >>
you can store what you find in a map of words (strings) to occurrences (unsigned number type)
when you access an entry in the map through a non-existing key, the map will helpfully create a new default-constructed value under that key for you; if the value happens to be a number, default-construction will set it to 0 (zero)
Have fun put this together!
Here's my hint. std::map will be your friend.
Here is an algorthm you could use, try coding something and put you results here. People can then help you get further.
Scan down the string collecting each letter until you get to a word boundary (say space or . or , etc).
Take that word and compare it to the words you've already found, if already found then add one to the count for that word. If it's not then add that word to the list of words found with a count of 1.
Carry on down the string
Well, you need a way of getting individual words from the input stream (perhaps something like an "input stream" method applied to the "standard input stream") and a way of storing those strings and counts in some sort of "collection".
My natural homework cynicism and general apathy towards life prevent me from adding more detail at the moment :-)
The meaning of any variables I use is fairly self-evident since I tend to use things like objectsRemaining or hasBeenOpened.