Comparing a char to chars in a list in C++ - c++

Is there a way to compare a char to each element in a list of chars?
char ch;
if(ch == 'a' || ch == 'b' || ch == 'c')
Is there some way to just do
if(ch is one of {a, b, c})

Why would you write lambdas or use a throwaway string object when you can just:
if (strchr("abc", ch))

Use : std::any_of
With C++11 :
std::string str="abc";
if(std::any_of(str.cbegin(), str.cend(),
[ch](const char& x){return x==ch; } ))
{
}
Or use a functor:
struct comp
{
comp(char x) :ch(x){}
bool operator()(const char& x) const
{
return x == ch;
}
char ch;
};
And then,
if(std::any_of(str.cbegin(), str.cend(),comp(ch) ))
{
}
Edit : std::any_of might not be efficient enough, just for sake of C++'s <algorithm> one can try this out too .

You could use std::find. Assuming chars is your character array and you need to find ch.
if(std::find(std::begin(chars), std::end(chars), ch) != std::end(chars))

One way to do it is searching a string, like this:
string abc("abc");
if (abc.find(ch) != string::npos) {
...
}

(This answer really only applies if you don't want to use C++ std lib constructs.)
In your specific case, you should be able to do:
if(ch >= 'a' && ch <= 'c')
I also have employed fall-through switch for this case:
switch(ch)
{
case 'a':
case 'b':
case 'c':
case 'e':
...
break;
}
Some people don't like fall-through switch/case statements, but I think its less error prone than a massive piece of boolean logic and will perform better than using a data structure for this purpose. The compiler is really good with dealing with switch statements.

If you can use variadic template arguments, which were introduced in C++11, then you can do something like this:
template <typename Key, typename Value>
inline bool in(const Key& key, const Value& value) {
return key == value;
}
template <typename Key, typename Value0, typename ...ValueN>
inline bool in(const Key& key, const Value0& value, ValueN &&...args) {
return (key == value ? true : in(key, std::forward<ValueN>(args)...));
}
I use it for strings like this:
if (in(some_string, "base", "os", "io", "coroutine", "debug")) ...
But other types that support comparison (char is one of them) should also work.
Hope it helps. Good Luck!

Just as another option, create a set with the characters, and check if it's contained there;
std::set<char> mySet = {'a','b','c'}; // C++11 initializer list
if(mySet.find('d') != mySet.end()) {
...
}

I'm sort of surprised that nobody suggested find_first_of.
char c('e');
// we can check if c is undesirable
const std::string unwanted("abc");
bool undesirable = (unwanted.find_first_of(c) != std::string::npos);
// OR we can check if c is desirable
const std::string wanted("def");
bool desirable = (wanted.find_first_of(c) != std::string::npos); //..or check if it's desirable.
I use this (maybe I shouldn't? folks?) for ignoring unwanted characters from a string iterator...
/** in and out are string iterators.
* skip over any undesirable characters by matching
* against desirable and looking for npos.
**/
const std::string ok("!+-./0123456789:^ABFIORmn");
while (ok.find_first_of(*in) == string::npos && in < out) {
in++;
}
A nice benefit of this is that by putting more frequent characters at the front of the string, there's a little bit of saving in time.

Related

Boost spirit parser of Fortran printed doubles

I am using num_list3.cpp from Boost Spirit examples. I am testing the variety of the double types it can parse. I used the following list:
1.2,0.2
.2,5.
1.e+23,.23E4
0e+10
1.3D+3
I noticed that it fails on parsing the last number 1.3D+3.
How could I set D as an exponent prefix of a double?
You can easily do that with Boost.Spirit. You just need to instantiate a real_parser with a custom policy that takes care of the "d|D" prefix. It could be as simple as:
template <typename Type>
struct fortran_policy : qi::real_policies<Type>
{
template <typename Iterator>
static bool parse_exp(Iterator& first, const Iterator& last)
{
if (first == last || (*first != 'e' && *first != 'E' && *first != 'd' && *first != 'D'))
return false;
++first;
return true;
}
};
Then you would simply need to use:
qi::real_parser<double,fortran_policy<double>> double_;
without needing to change anything else(although that semantic action seems rather unnecessary).
Live on ideone
You can't.
Although FORTRAN apparently uses this, it's not widely used in any other context, and is not ISO-standardised scientific notation.

Sorting a string with std::sort so that capital letters come after lower case

I'd like to sort a vector so that the capital letters follow the lower case letter. If I have something like
This is a test
this is a test
Cats
cats
this thing
I would like the output to be
cats
Cats
this is a test
This is a test
this thing
The standard library sort will output
Cats
This is a test
cats
this is a test
this thing
I want to pass a predicate to std::sort so that it compares the lowercase version of the strings that I pass as arguments.
bool compare(std::string x, std::string y)
{
return lowercase(x) < lowercase(y);
}
I tried lowering each character within the function and then making the comparison but it didn't work. I would like to test this approach by converting the string to lowercase by some other method. How do I convert strings into lowercase?
EDIT::
Actually I figured out the problem. This works. When I first wrote the function, instead of ref = tolower(ref) I had tolower(ref) without reassigning to ref so it wasn't doing anything.
bool compare(std::string x, std::string y)
{
for(auto &ref:x)
ref = tolower(ref);
for(auto &ref:y)
ref = tolower(ref);
return x < y;
}
EDIT::
This code actually sorts with the capital letter first sometimes and the capital letter second in other times so it doesn't solve the problem completely.
The usual way to do this would be to build a collation table. That's just a table giving the relative ordering of every character. In your case, you want each upper-case letter immediately following the corresponding lower-case letter.
We can do that something like this:
class comp_char {
std::vector<int> collation_table;
public:
comp_char() : collation_table(std::numeric_limits<unsigned char>::max()) {
std::iota(collation_table.begin(), collation_table.end(), 0);
for (int i = 0; i < 26; i++) {
collation_table['a' + i] = i * 2;
collation_table['A' + i] = i * 2 + 1;
}
}
bool operator()(unsigned char a, unsigned char b) {
return collation_table[a] < collation_table[b];
}
};
For the moment, I've ignored the (possibly knotty) problem of the relative ordering of letters to other characters. As it's written, everything else sorts before letters, but it would be pretty easy to change that so (for example) letters sorted before anything else instead. It probably doesn't make a huge difference either way though -- most people don't have strong expectations about whether 'a' < ';' or not.
In any case, once the collation table is built and usable, you want to use it to compare strings:
struct cmp_str {
bool operator()(std::string const &a, std::string const &b) {
comp_char cmp;
size_t i = 0;
while (a[i] == b[i] && i < a.size())
++i;
return cmp(a[i], b[i]);
}
};
...which we can use to do sorting, something like this:
int main(){
std::vector<std::string> inputs {
"This is a test",
"this is a test",
"Cats",
"cats",
"this thing"
};
std::sort(inputs.begin(), inputs.end(), cmp_str());
std::copy(inputs.begin(), inputs.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
For the moment, I've only written the collation table to handle the basic US-ASCII letters. For real use, you'd typically want to have things like letters with accents and such sort next to their corresponding un-accented equivalents. For that, you typically end up pre-building the table to (partially) match things like the Unicode specification for how things should be ordered.
Note that this output doesn't quite match what the original question says is desired, but I think in this case the question has a mistake. I can't see any way it would be even marginally reasonable to produce an order like:
this is a test
This is a test
this thing
This has "T" sorting both after and before "t", which doesn't seem to make sense (or at least doesn't fit with a lexical sort, which is what people nearly always want for strings).
The simplest solution is to use the collation-aware sorting provided by the standard locale object.
A locale's operator()(std::string, std::string) is exactly the locale's collation-aware comparison operator, so you can just insert it directly into your call to std::sort:
// Adjust to the locale you actually want to use
std::sort(strings.begin(), strings.end(), std::locale("en_US.UTF-8"));
Example on ideone
Your solution is almost there, you just need to make a special case if the lower case version of the strings are equal:
std::string to_lower(std::string s)
{
for (auto & c : s)
c = std::tolower(c);
return s;
}
bool string_comp(std::string const & lhs, std::string const & rhs)
{
auto lhs_lower = to_lower(lhs);
auto rhs_lower = to_lower(rhs);
if (lhs_lower == rhs_lower)
return rhs < lhs;
return lhs_lower < rhs_lower;
}
This could use some optimization. Copying the string is not necessary. You can, of course, do a case insensitive comparison in place. But that is feature is not conveniently available in the standard library, so I'll leave that exercise up to you.
To be clear, I was aiming at the usual lexicographic type comparison but somehow make uppercase follow the lowercase if the strings were identical otherwise.
This requires a two-steps comparison then:
compare the strings in case-insensitive mode
if two strings are equal in case-insensitive mode, we want the reverse result of a case sensitive comparison (which puts upper-case first)
So, the comparator gives:
class Comparator {
public:
bool operator()(std::string const& left, std::string const& right) {
size_t const size = std::min(left.size(), right.size());
// case-insensitive comparison
for (size_t i = 0; i != size; ++i) {
if (std::tolower(left[i]) < std::tolower(right[i])) { return true; }
}
if (left.size() != right.size()) { return size == left.size(); }
// and now, case-sensitive (reversed)
return right < left;
}
}; // class Comparator
You need to do the comparison one char at a time, stopping at the first different char and then returning the result depending on the case conversion first, and on original char otherwise:
bool mylt(const std::string& a, const std::string& b) {
int i=0, na=a.size(), nb=b.size();
while (i<na && i<nb && a[i]==b[i]) i++;
if (i==na || i==nb) return i<nb;
char la=std::tolower(a[i]), lb=std::tolower(b[i]);
return la<lb || (la==lb && a[i]<b[i]);
}
Warning: untested breakfast code
Either use locals that already have the ordering you want, or write a character by character comparison function then use std::lexicographical_compare to turn it into a string comparison function.
I would try locals first, but if that proved frustrating the lexicographic is not horrible.
To compare chqracters, create two tuples or pairs of lower_case_letter, unchanged_letter, and call < on it. This will first order by lower case, then if that fails by the unchanged. I forget what order the upper vs lower will sort in: but if the order is backwards, just swap which lower case letter gets paired with which upper case letter, and you'll reverse the order!

Using std::map inside switch case

I have this:
map<string,int> a;
int b;
And i'd like to make this:
switch(b)
{
case a["someStr1"]:
someCode1();
break;
case a["someStr2"]:
someCode2();
break;
etc.
}
But it doesn't compiles. How to implement this correctly?
switch conditions need to be constants, so what you want to do here is not possible.
You're better off using some if statements.
switch/case are meant for constants (e.g., enum, ints etc.).
You can use the map<>::iterator to run through the values and compare with b.
for(map<string,int>::const_iterator it = a.begin(), end = a.end(); it != end; it++)
{
if(it->second == b)
{
...
break;
}
}
This way you can avoid the code duplication for comparison, if your a is large enough.
Also, you can explore the option of replacing for loop with for_each.
You can't.
Expression after case in a switch statement must be integral compile-time constant. So a literal (42), const int variable initialized with a literal (const int x = 66 ... case x:) or enum value. And thats about it.
The reason this is so strict is efficiency. Compilers usually create labels for each case and if you know the value for each label at compile time, you can make some nice optimizations that avoid most of the overhead a normal code branching has.
In your case just go with if-else:
if(b == a["someStr1"]) {
//...
} else if(b == a["someStr2"]) {
//...
} // and so on

comparison operator

It may be silly question.
Is there any way to give comparison operator at runtime using string variable.
Suppose i have a data of salaries in vector.
vector < int > salary;
Input:
salary[i] != /* ==,>,<,>=,<= (any comparison operator)) */ 9000.
The input given like above. I store the comparison operator in string str. str = (any comparison operator). Is there any way to check like this without if and switch.
salary str 9000
You can create a map with operator-strings as keys and function objects for corresponding comparison operations as values.
Creating a map:
std::map<std::string, boost::function<bool(int, int)> > ops;
ops["=="] = std::equal_to<int>();
ops["!="] = std::not_equal_to<int>();
ops[">"] = std::greater<int>();
ops["<"] = std::less<int>();
ops[">="] = std::greater_equal<int>();
ops["<="] = std::less_equal<int>();
Using it:
bool resultOfComparison = ops[str](salary[i], 9000);
(See this link for a complete working example.)
EDIT:
As #sbi said in the comments below, accessing a map using map[key] will create an entry if the key didn't exist. So use it = map.find(key) instead. If the result is equal to map.end() the key wasn't found, otherwise value is it->second. Take note of this while adapting this solution to your needs.
Still, you might have a std::map with a mapping between contents of your strings and pointers to your operators.
No. Not possible. Unless you parse the given input and call the corresponding operation. In any case, you would need a if - else statement.
You need to have something of sort of EVAL in your programming language, which evaluates your strings.
EDIT: C++ does not have EVAL to support your cause.
No, compiled languages like C++ don't work like that. There has to be code in the final executable that does the comparison, and by design C++ doesn't generate that code unless it's actually in the source program.
You can also create a functor which will take string as a constructor or factory which will produce different functors (depending on flexibility you need).
So something like:
:Input
Comp cmp = Comp(str);
if (cpm(salary[i], 9000))
{
cout << "wow";
}
You'd have to "hack" in this required eval! ;) i.e.
template <typename T>
bool eval_op(const string& op, const T& lhs, const T& rhs)
{
switch(op.size())
{
case 2:
{
switch(op[1])
{
case '=':
{
switch(op[0])
{
case '=': return lhs == rhs;
case '!': return lhs != rhs;
case '>': return lhs >= rhs;
case '<': return lhs <= rhs;
}
}
default: throw("crazy fool!");
};
}
case 1:
{
switch(op[0])
{
case '>': return lhs > rhs;
case '<': return lhs < rhs;
default: throw ("crazy fool!");
}
}
default: throw ("crazy fool!");
}
return false;
}
DISCLAIMER: I've not tested this... but it's an idea...
In this particular situation an if-else branch is your simplest solution. This is simply because there are only so many comparison alternatives, and you can be sure none others will ever exist. In essence your code should be along the lines of
if( in == "==" )
cond = salary[i] == 9000;
else if( in == "!=" )
cond = salary[i] != 9000;
// ...
else
// throw, return -1, raise a flag or burst out in laughter
This is in fact safer than a dynamic eval() because here you sanitize the input. You make sure there is no malicious code in there, along the lines of a Little Bobby Tables attack.
Granted, you could use polymorphism here, but the point of polymorphism is support open-ended type alternatives. When you wish to add a case, polymorphism allows you to do that with ease. But you'd need to do some work to get foundations up, and here there are exactly 6 comparison alternatives. Or 7, if you want to add support for an arbitrary predicate.

How to use a hash_map with case insensitive unicode string for key?

I'm very new to STL, and pretty new to C++ in general. I'm trying to get the equivalent of a .NET Dictionary<string, value>(StringComparer.OrdinalIgnoreCase) but in C++. This is roughly what I'm trying:
stdext::hash_map<LPCWSTR, SomeStruct> someMap;
someMap.insert(stdext::pair<LPCWSTR, SomeStruct>(L"a string", struct));
someMap.find(L"a string")
someMap.find(L"A STRING")
The trouble is, neither find operation usually works (it returns someMap.end()). It seems to sometimes work, but most of the time it doesn't. I'm guessing that the hash function the hash_map is using is hashing the memory address of the string instead of the content of the string itself, and it's almost certainly not case insensitive.
How can I get a dictionary-like structure that uses case-insensitive keys and can store my custom struct?
The hash_map documentation you link to indicates that you can supply your own traits class as a third template parameter. This must satisfy the same interface as hash_compare.
Scanning the docs, I think that what you have to do is this, which basically replaces the use of StringComparer.OrdinalIgnoreCase you had in your Dictionary:
struct my_hash_compare {
const size_t bucket_size = 4;
const size_t min_buckets = 8;
size_t operator()(const LPCWSTR &Key) const {
// implement a case-insensitive hash function here,
// or find something in the Windows libraries.
}
bool operator()(const LPCWSTR &Key1, const LPCWSTR &Key2) const {
// implement a case-insensitive comparison function here
return _wcsicmp(Key1, Key2) < 0;
// or something like that. There's warnings about
// locale plastered all over this function's docs.
}
};
I'm worried though that the docs say that the comparison function has to be a total order, not a strict weak order as is usual for sorted containers in the C++ standard libraries. If MS really means a total order, then the hash_map might rely on it being consistent with operator==. That is, they might require that if my_hash_compare()(a,b) is false, and my_hash_compare()(b,a) is false, then a == b. Obviously that's not true for what I've written, in which case you're out of luck.
As an alternative, which in any case is probably more efficient, you could push all the keys to a common case before using them in the map. A case-insensitive comparison is more costly than a regular string comparison. There's some Unicode gotcha to do with that which I can never quite remember, though. Maybe you have to convert -> lowercase -> uppercase, instead of just -> uppercase, or something like that, in order to avoid some nasty cases in certain languages or with titlecase characters. Anyone?
Also as other people said, you might not really want LPCWSTR as your key. This will store pointers in the map, which means that anyone who inserts a string has to ensure that the data it points to remains valid as long as it's in the hash_map. It's often better in the long run for hash_map to keep a copy of the key string passed to insert, in which case you should use wstring as the key.
There was some great information given here. I gathered bits and pieces from the answers and put this one together:
#include "stdafx.h"
#include "atlbase.h"
#include <map>
#include <wchar.h>
typedef std::pair<std::wstring, int> MyPair;
struct key_comparer
{
bool operator()(std::wstring a, std::wstring b) const
{
return _wcsicmp(a.c_str(), b.c_str()) < 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::map<std::wstring, int, key_comparer> mymap;
mymap.insert(MyPair(L"GHI",3));
mymap.insert(MyPair(L"DEF",2));
mymap.insert(MyPair(L"ABC",1));
std::map<std::wstring, int, key_comparer>::iterator iter;
iter = mymap.find(L"def");
if (iter == mymap.end()) {
printf("No match.\n");
} else {
printf("match: %i\n", iter->second);
}
return 0;
}
If you use an std::map instead of the non-standard hash_map, you can set the comparison function to be used when doing the binary search:
// Function object for case insensitive comparison
struct case_insensitive_compare
{
case_insensitive_compare() {}
// Function objects overloader operator()
// When used as a comparer, it should function as operator<(a,b)
bool operator()(const std::string& a, const std::string& b) const
{
return to_lower(a) < to_lower(b);
}
std::string to_lower(const std::string& a) const
{
std::string s(a);
std::for_each(s.begin(), s.end(), char_to_lower);
return s;
}
void char_to_lower(char& c) const
{
if (c >= 'A' && c <= 'Z')
c += ('a' - 'A');
}
};
// ...
std::map<std::string, std::string, case_insensitive_compare> someMap;
someMap["foo"] = "Hello, world!";
std::cout << someMap["FOO"] << endl; // Hello, world!
LPCWSTR is a pointer to a null-terminated array of unicode characters and probably not what you want in this case. Use the wstring specialization of basic_string instead.
For case-insensitivity, you would need to convert the keys to all upper case or all lower case before you insert and search. At least I don't think you can do it any other way.