Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I was looking for replacing a character in a string with a character in another string comparing to another string.
Well, hard to describe this, a code would be better :
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
std::string keyboard = "AZERTYUIOPQSDFGHJKLMWXCVBNazertyuiopqsdfghjklmwxcvbn";
std::string change(std::string str)
{
for (short i = 0; i < alphabet.length(); i++)
{
std::cout << str[i] << std::endl;
}
std::cout << str << std::endl;
system("PAUSE");
return str;
}
Well, I don't think it is understandable, so what I try to do is :
Find (maybe Find() ?) the letter in str and get the i-variable in alphabet.
With the i-variable want to get the pos and then get the letter in the keyboard string.
Hope you understand what I mean, and thank you.
I though about replace(), find() and swap(), but didn't work, I maybe did something wrong.
Thank you in advance !
EDIT : Well, I was sure you won't understand anything, imagine str = "Hello", I want to replace H per Y (alphabet = H -> keyboard = I)? (alphabet get the position of the H in the alphabet string, we memorise this position in i, and we keyboard[i]), this is what I want to do.
I propose
template <typename InputIterator,
typename BidirIterator,
typename ForwardIterator>
InputIterator substitute( InputIterator first, InputIterator last,
BidirIterator key_first, BidirIterator key_last,
ForwardIterator val_first )
{
for (; first != last; ++first)
{
auto&& ref = *first;
auto i = std::lower_bound( key_first, key_last, ref );
if (i == key_last || *i != ref)
return first;
ref = *std::next(val_first, std::distance(key_first, i));
}
return last;
}
This assumes that [key_first, key_last) is sorted and that val_first refers to a range that is at least as long as [key_first, key_last).
Demo.
The idea is that we iterate through all elements of a range using iterators whose type is to be determined - i.e. we can use both char const[]s and std::vector<char>s. We pick the current element and use a binary search to find that element within the key set. Then we use the offset to access the substitution counterpart in the value set, and assign that to our original element.
We use lower_bound to do the binary search. It doesn't itself constitute one, so we have to apply some checks to the return value to ensure the iterator refers to the correct value. If we couldn't find the key then the iterator to the first non-working element is returned. (That can be the past-the-end iterator.)
The avove is a general method that works for arbitrary key/value sets: For alphabetic shuffling there are (platform dependent) methods using lookup tables. Rustically this could look like this:
template <typename InputIterator>
void substitute( InputIterator first, InputIterator last,
char const* values )
{
char lookup[UCHAR_MAX+1];
for (int c = 0; c != sizeof lookup; ++c)
if (std::isupper(c))
lookup[c] = values[c - 'A'];
else if (std::islower(c))
lookup[c] = values[c - 'a' + 26];
else
lookup[c] = c;
// Further adjustments to the table can be made here
std::transform( first, last, first,
[&] (unsigned char c) {return lookup[c];} );
}
Demo. It depends on stuff that normal character sets should easily suffice. The table can also be created elsewhere and passed to transform via the unwrapped one-liner. This is especially efficient for large string transformations as no branching is necessary in the implicit loop in transform.
So, you want to replace every char in your string with a char from keyboard string using original char's position in alphabet?
I would consider using a map alphabet char to keyboard char. Then iterate through string and replace its characters.
#include <string>
#include <algorithm>
#include <map>
int main(int argc, char* argv[])
{
std::map<char, char> alphabetToKeyboard;
alphabetToKeyboard['A'] = 'A';
alphabetToKeyboard['B'] = 'Z';
alphabetToKeyboard['C'] = 'E';
std::string str = "ABC";
std::transform(str.begin(), str.end(), str.begin(), [&alphabetToKeyboard](char c) {
return alphabetToKeyboard[c];
});
return 0;
}
Related
I am trying to validate a single-line input string in C++11 to see if it contains any leading / trailing whitespaces. My code now looks like this:
bool is_valid(const std::string& s) {
auto start = s.begin();
auto end = s.end();
if (std::isspace(*start) || std::isspace(*end)) {
return false;
}
return true;
}
int main() {
std::string name{};
std::getline(std::cin, name);
if (!is_valid(name)) {
std::cout << "Invalid!";
}
return 0;
}
But now the program can only detect leading whitespaces. For example, for John it would print Invalid! but for Mary it would classify it as valid input, which is not. Does anyone know what's wrong with my program?
A simple test for std::string::front() and std::string::back() could have been done after testing for the empty string:
bool is_valid(const std::string& s)
{
return s.empty() ||
(!std::isspace(static_cast<unsigned char>(s.front())) &&
!std::isspace(static_cast<unsigned char>(s.back())));
}
The end iterator does not point to an element in the container. It points one past the last element. You may not dereference the end iterator. For a std::string you can use it's operator[]:
char last_char = s[s.size()-1];
advance the begin iterator:
auto it = s.begin() + s.size()-1;
char last_char = *it;
or decrement the end iterator:
auto it = s.end() -1;
char last_char = *it;
Other alternatives are back() or using the reverse iterator rbegin().
Note that they all require s.size() != 0. For an empty string s.begin() == s.end(). You should check that first in the function and return true for that case.
s.end() is one pass the end of the string just like any other containers in C++, so accessing it invokes undefined behavior. You need to use std::prev(s.end()) instead (which is valid only the string contains at least 1 character though, so you need to check the string length first)
.end is used to get an iterator to past the last element. You can use std::string::rbegin to get the last element.
auto end = s.rbegin();
NB: std::string::starts_with and std::string::ends_with are available from C++20.
Yes, .end() is to the past-the-end element. Then why not using .back() instead?
bool is_valid(std::string const& str) {
return str.empty() || !(std::isspace(str.front()) || std::isspace(str.back()));
}
If I wanted to iterate over individual words in a string (separated by whitespace), then the obvious solution would be:
std::istringstream s(myString);
std::string word;
while (s >> word)
do things
However that's quite inefficient. The entire string is copied while initializing the string stream, and then each extracted word is copied one at a time into the word variable (which is close to copying the entire string for a second time). Is there a way to improve on this without manually iterating over each character?
In most cases, copying represents a very small percentage of the overall costs, so having a clean, highly readable code becomes more important. In rare cases when the time profiler tells you that copying creates a bottleneck, you can iterate over characters in the string with some help from the standard library.
One approach that you could take is to iterate with std::string::find_first_of and std::string::find_first_not_of member functions, like this:
const std::string s = "quick \t\t brown \t fox jumps over the\nlazy dog";
const std::string ws = " \t\r\n";
std::size_t pos = 0;
while (pos != s.size()) {
std::size_t from = s.find_first_not_of(ws, pos);
if (from == std::string::npos) {
break;
}
std::size_t to = s.find_first_of(ws, from+1);
if (to == std::string::npos) {
to = s.size();
}
// If you want an individual word, copy it with substr.
// The code below simply prints it character-by-character:
std::cout << "'";
for (std::size_t i = from ; i != to ; i++) {
std::cout << s[i];
}
std::cout << "'" << std::endl;
pos = to;
}
Demo.
Unfortunately, the code becomes a lot harder to read, so you should avoid this change, or at least postpone it until it becomes requried.
Using boost string algorithms we can write it as follows.
The loop doesn't involve any copying of the string.
#include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>
int main()
{
std::string s = "stack over flow";
auto it = boost::make_split_iterator( s, boost::token_finder(
boost::is_any_of( " " ), boost::algorithm::token_compress_on ) );
decltype( it ) end;
for( ; it != end; ++it )
{
std::cout << "word: '" << *it << "'\n";
}
return 0;
}
Making it C++11-ish
Since pairs of iterators are so oldschool nowadays, we may use boost.range to define some generic helper functions. These finally allow us to loop over the words using range-for:
#include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/range/iterator_range_core.hpp>
template< typename Range >
using SplitRange = boost::iterator_range< boost::split_iterator< typename Range::const_iterator > >;
template< typename Range, typename Finder >
SplitRange< Range > make_split_range( const Range& rng, const Finder& finder )
{
auto first = boost::make_split_iterator( rng, finder );
decltype( first ) last;
return { first, last };
}
template< typename Range, typename Predicate >
SplitRange< Range > make_token_range( const Range& rng, const Predicate& pred )
{
return make_split_range( rng, boost::token_finder( pred, boost::algorithm::token_compress_on ) );
}
int main()
{
std::string str = "stack \tover\r\n flow";
for( const auto& substr : make_token_range( str, boost::is_any_of( " \t\r\n" ) ) )
{
std::cout << "word: '" << substr << "'\n";
}
return 0;
}
Demo:
http://coliru.stacked-crooked.com/a/2f4b3d34086cc6ec
If you want to have it as fast as possible, you need to fall back to the good old C function strtok() (or its thread-safe companion strtok_r()):
const char* kWhiteSpace = " \t\v\n\r"; //whatever you call white space
char* token = std::strtok(myString.data(), kWhiteSpace);
while(token) {
//do things with token
token = std::strtok(nullptr, kWhiteSpace));
}
Beware that this will clobber the contents of myString: It works by replacing the first delimiter character after each token with a terminating null byte, and returning a pointer to the start of the tokens in turn. This is a legacy C function after all.
However, that weakness is also its strength: It does not perform any copy, nor does it allocate any dynamic memory (which likely is the most time consuming thing in your example code). As such, you won't find a native C++ method that beats strtok()'s speed.
What about spliting the string? You can check this post for more information.
Inside this post there is a detailed answer about how to split a string in tokens. In this answer maybe you could check the second way using iterators and the copy algorithm.
I am trying to check if char exists in vector of chars, and if so, to get it`s number. I have done the first part (check if char exists):
char letter(a);
string word;
vector<char>vWord(word.begin(), word.end());
if(find(vWord.begin(), vWord.end(), letter) != vWord.end()){}
But I have no idea how to get the position. Any help is appreciated.
Save the iterator and do some math on it:
vector<char>::iterator itr = find(vWord.begin(), vWord.end(), letter);
if(itr != vWord.end())
{
int index = itr - vWord.begin();
}
However do note that std::string already has a find method.
You're almost there. You already have an iterator pointing to that character (returned by find), so you can use std::distance to find the distance:
char letter(a);
string word;
vector<char>vWord(word.begin(), word.end());
auto it = find(vWord.begin(), vWord.end(), letter);
if (it != vWord.end())
{
size_t index = std::distance(vWord.begin(), it);
}
For random-access iterators (such as those used by std::vector), std::distance(a, b) is a constant-time operation and is implemented by doing b - a.
Side note: you can do std::find and iterator operations on std::string directly; it's a perfectly fine container in its own right.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
How can I derive all possible matches of a regular expression
For example:
((a,b,c)o(m,v)p,b)
The strings generated from above expression would be:
aomp
bomp
comp
aovp
bovp
covp
b
Your steps are pretty straight forward though implementing them may take a bit of work:
Create a recursive function which extracts the string between the first set of parenthesis it comes to: https://stackoverflow.com/a/28863720/2642059
In the function split this strings on ',' into a vector<string> and return it: https://stackoverflow.com/a/28880605/2642059
Before returning test if it is necessary to recurse because of a nested parenthesis, one string must be added to the return for each possible combination returned from recursed functions
EDIT:
Say my input string was "(bl(ah,eck,le),yap)"
The first function would extract the string: "bl(ah,eck,le),yap"
Before returning it would search for nested parenthesis, this would cause it to recurse:
The second function would extract the string: "ah,eck,le"
Before returning it would search for nested parenthesis and find none
It would return an vector<string>: ["ah","eck","le"]
The first function would now contain: "bl["ah","eck","le"],yap"
It would not find anymore parenthesis to extract, so it would go to expanding all internal combinations: "["blah","bleck","blle"],yap"
It could now split the string and return: ["blah","bleck","blle","yap"]
The return from your first function is your result.
EDIT:
Glad you solved it I wrote up a two state machine to solve it as well so I figured I could post it here for your comparison:
const char* extractParenthesis(const char* start, const char* finish){
int count = 0;
return find_if(start, finish, [&](char i){
if (i == '('){
count++;
}
else if (i == ')'){
count--;
}
return count <= 0; });
}
vector<string> split(const char* start, const char* finish){
const char delimiters[] = ",(";
const char* it;
vector<string> result;
do{
for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
it != finish && *it == '(';
it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
auto&& temp = interpolate(start, it);
result.insert(result.end(), temp.begin(), temp.end());
start = ++it;
} while (it <= finish);
return result;
}
vector<string> interpolate(const char* start, const char* finish){
vector<string> result{ 1, string{ start, find(start, finish, '(') } };
for (auto it = start + result[0].size();
it != finish;
it = find(++start, finish, '('),
for_each(result.begin(), result.end(), [&](string& i){ i += string{ start, it }; })){
start = extractParenthesis(it, finish);
auto temp = split(next(it), start);
const auto size = result.size();
result.resize(size * temp.size());
for (int i = result.size() - 1; i >= 0; --i){
result[i] = result[i % size] + temp[i / size];
}
}
return result;
}
Depending upon your compiler you'll need to forward declare these since they call each other. This will also crash fantastically if the input string is malformed. And it can't handle escaped control characters.
Anyway you can call it like this:
const char test[] = "((a,b,c)o(m,v)p,b)";
auto foo = interpolate(begin(test), end(test));
for (auto& i : foo){
cout << i << endl;
}
I wrote a function to check whether a word is palindrome or not but "unexpectedly", that function failed quite badly, here it is:
bool isPalindrome (const string& s){
string reverse = "";
string original = s;
for (string_sz i = 0; i != original.size(); ++i){
reverse += original.back();
original.pop_back();
}
if (reverse == original)
return true;
else
return false;
}
It gives me "string iterator offset out of range error" when you pass in a string with only one character and returns true even if we pass in an empty string (although I know its because of the intialisation of the reverse variable) and also when you pass in an unassigned string for example:
string input;
isPalindrome(input);
Later, I found a better function which works as you would expect:
bool found(const string& s)
{
bool found = true;
for (string::const_iterator i = s.begin(), j = s.end() - 1; i < j; ++i, --j) {
if (*i != *j)
found = false;
}
return found;
}
Unlike the first function, this function correctly fails when you give it an unassigned string variable or an empty string and works for single characters and such...
So, good people of stackoverflow please point out to me why the first function is so bad...
Thank You.
for (string_sz i = 0; i != original.size(); ++i) {
reverse += original.back();
original.pop_back();
}
original.size() changes as you pop elements off the back. Effectively, you keep incrementing i and decrementing original.size(); they may never be equal.
if (reverse == original)
This will never be true since you've just removed all of the elements from original and added them in reverse order to reverse. original will always be empty at this point.
You're found function could very well rely on the STL std::compare function and on the begin()/end() rbegin()/rend() functions of the string. and could be a one line function :
return std::equal(s.begin(), s.end(), s.rbegin());
The std::equal() function compares two ranges of the same length.
The begin()/end() functions provide forward iterators while rbegin() provides a reverse iterator, ie an iterator that starts at the end of the string and goes to the beginning.
This is probably not what you want, but reverse is already implemented as an algorithm in STL:
bool isPalindrome( const std::string & str )
{
std::string rev( str );
std::reverse( rev.begin(), rev.end() );
return str==rev;
}
As #James McNellis points out, this can be further condensed (without needing any algorithm) by constructing the reversed string directly with reverse iterators on the original string:
bool isPalindrome( const std::string & str )
{
return str == std::string( str.rbegin(), str.rend() );
}
The loop that purports to reverse the string doesn't in fact do so. As you're removing items from the list, you're also incrementing i. In some cases I imagine it's possible for i to skip past the current size and iterate forever.
Instead of your loop, you can use reverse:
std::reverse(original.begin(), original.end());
And then do the rest of the work. It's up to your requirements if an empty string is a palindrome or not.
Your solutions are far too complicated ;)
bool is_palindrome(std::string const& s) {
if (s.empty()) return false; // if this is required.
return !lexicographical_compare(s.begin(), s.end(), s.rbegin(), s.rend());
}
Edit: Or, as Etienne noted, just use std::equal ...
bool is_palindrome(std::string const& s) {
if (s.empty()) return false; // if this is required.
return equal(s.begin(), s.end(), s.rbegin());
}