String manipulation with permutation - c++

Given that a string can vary from 2 to 7 characters. I need to fill * to make it up to 7 characters and store all the permutations to a container. In addition, it cannot accept three or more continuous * (e.g. ABCD*** won't be pushed to the container). Also the order of the characters cannot be changed.
For example, a string 'ABCDEF' filled with '*' could have the following permutations:
ABCDEF*
ABCDE*F
ABCD*EF
ABC*DEF
AB*CDEF
A*BCDEF
*ABCDEF
A string 'ABCD' filled with '*' could have the following permutations (note: ABCD*** not accepted because it has 3 continuous '*'):
ABC*D**
ABC**D*
AB*CD**
AB*C*D*
AB*C**D
...
**A*BCD
(...total 30 items will be pushed to the container)
I try to write a program to do this. If the string are 2 characters long, I need to loop 2 times. For example,
void loop_two_times(const std::string & str = "AB")
{
for (int i = 0; i < 7; i++)
{
for (int j = i+1; j < 7; j++)
{
std::string ustring = get7StarsString(); // this string will contain 7 stars
ustring[i] = str[0];
ustring[j] = str[1];
if (!tooMuchStars(ustring))
{
permutations.push_back(ustring);
}
else {} // do nothing
}
}
}
If the string are N characters long, I need to loop N times. However, I do not want to check the number of characters and write the functions to loop 2,3,4,5,6 times. e.g.
switch (numOfChars)
{
case 2: loop_two_times(); break;
case 3: loop_three_times(); break;
case 4: loop_four_times(); break;
case 5: loop_five_times(); break;
case 6: loop_six_times(); break;
}
Please could you kindly suggest how can I implement this efficently?
Many thanks!

You may use the following: (https://ideone.com/L209jH)
// return a string with '0' replaced with letter, and '1' with '*'.
std::string convert(const std::string& order, const std::string& s)
{
std::string res;
std::size_t pos = 0;
for (std::size_t i = 0; i != order.size(); ++i) {
if (order[i] == '1') {
res += '*';
} else {
res += s[pos++];
}
}
return res;
}
void print_combinaison(const std::string& msg)
{
std::string s(msg.size(), '0');
s.resize(7, '1');
// s is a string of 7 letter with '0' (representing letter)
// and '1' representing '*'
// initial value of s is one of 0000000, 0000001, 0000011, 0000111,
// 0001111, 0011111, 0111111 or 1111111.
do
{
if (s.find("111") != std::string::npos) continue;
std::cout << convert(s, msg) << std::endl;
} while (std::next_permutation(begin(s), end(s)));
}

Related

find the maximum number of words in a sentence from a paragraph with C++

I am trying to find out the maximum number of words in a sentence (Separated by a dot) from a paragraph. and I am completely stuck into how to sort and output to stdout.
Eg:
Given a string S: {"Program to split strings. By using custom split function. In C++"};
The expected output should be : 5
#define max 8 // define the max string
string strings[max]; // define max string
string words[max];
int count = 0;
void split (string str, char seperator) // custom split() function
{
int currIndex = 0, i = 0;
int startIndex = 0, endIndex = 0;
while (i <= str.size())
{
if (str[i] == seperator || i == str.size())
{
endIndex = i;
string subStr = "";
subStr.append(str, startIndex, endIndex - startIndex);
strings[currIndex] = subStr;
currIndex += 1;
startIndex = endIndex + 1;
}
i++;
}
}
void countWords(string str) // Count The words
{
int count = 0, i;
for (i = 0; str[i] != '\0';i++)
{
if (str[i] == ' ')
count++;
}
cout << "\n- Number of words in the string are: " << count +1 <<" -";
}
//Sort the array in descending order by the number of words
void sortByWordNumber(int num[30])
{
/* CODE str::sort? std::*/
}
int main()
{
string str = "Program to split strings. By using custom split function. In C++";
char seperator = '.'; // dot
int numberOfWords;
split(str, seperator);
cout <<" The split string is: ";
for (int i = 0; i < max; i++)
{
cout << "\n initial array index: " << i << " " << strings[i];
countWords(strings[i]);
}
return 0;
}
Count + 1 in countWords() is giving the numbers correctly only on the first result then it adds the " " whitespace to the word count.
Please take into consideration answering with the easiest solution to understand first. (std::sort, making a new function, lambda)
Your code does not make a sense. For example the meaning of this declaration
string strings[max];
is unclear.
And to find the maximum number of words in sentences of a paragraph there is no need to sort the sentences themselves by the number of words.
If I have understood correctly what you need is something like the following.
#include <iostream>
#include <sstream>
#include <iterator>
int main()
{
std::string s;
std::cout << "Enter a paragraph of sentences: ";
std::getline( std::cin, s );
size_t max_words = 0;
std::istringstream is( s );
std::string sentence;
while ( std::getline( is, sentence, '.' ) )
{
std::istringstream iss( sentence );
auto n = std::distance( std::istream_iterator<std::string>( iss ),
std::istream_iterator<std::string>() );
if ( max_words < n ) max_words = n;
}
std::cout << "The maximum number of words in sentences is "
<< max_words << '\n';
return 0;
}
If to enter the paragraph
Here is a paragraph. It contains several sentences. For example, how to use string streams.
then the output will be
The maximum number of words in sentences is 7
If you are not yet familiar with string streams then you could use member functions find, find_first_of, find_first_not_of with objects of the type std::string to split a string into sentences and to count words in a sentence.
Your use case sounds like a reduction. Essentially you can have a state machine (parser) that goes through the string and updates some state (e.g. counters) when it encounters the word and sentence delimiters. Special care should be given for corner cases, e.g. when having continuous multiple white-spaces or >1 continous full stops (.). A reduction handling these cases is shown below:
int max_words_in(std::string const& str)
{
// p is the current and max word count.
auto parser = [in_space = false] (std::pair<int, int> p, char c) mutable {
switch (c) {
case '.': // Sentence ends.
if (!in_space && p.second <= p.first) p.second = p.first + 1;
p.first = 0;
in_space = true;
break;
case ' ': // Word ends.
if (!in_space) ++p.first;
in_space = true;
break;
default: // Other character encountered.
in_space = false;
}
return p; // Return the updated accumulation value.
};
return std::accumulate(
str.begin(), str.end(), std::make_pair(0, 0), parser).second;
}
Demo
The tricky part is deciding how to handle degenerate cases, e.g. what should the output be for "This is a , ,tricky .. .. string to count" where different types of delimiters alternate in arbitrary ways. Having a state machine implementation of the parsing logic allows you to easily adjust your solution (e.g. you can pass an "ignore list" to the parser and update the default case to not reset the in_space variable when c belongs to that list).
vector<string> split(string str, char seperator) // custom split() function
{
size_t i = 0;
size_t seperator_pos = 0;
vector<string> sentences;
int word_count = 0;
for (; i < str.size(); i++)
{
if (str[i] == seperator)
{
i++;
sentences.push_back(str.substr(seperator_pos, i - seperator_pos));
seperator_pos = i;
}
}
if (str[str.size() - 1] != seperator)
{
sentences.push_back(str.substr(seperator_pos + 1, str.size() - seperator_pos));
}
return sentences;
}

Roman Numerals to Arabic (vinculum) - reading characters in a string

I am currently working on a project that converts Roman Numerals to Arabic Numbers and vice versa.
I am also responsible to implement concepts like vinculum, where if you put a bar on top of a Roman numeral, the numbers below will be multiplied by 1,000.
The problem I am having is I can get only one side working, meaning:
I can either just convert from Roman Numeral to Arabic without Vinculum:
ex. I = 1, II = 2
However, when this works my vinculum code does not work.
Here is a snippet of my code:
int romanToDecimal(char input[], size_t end) {
int roman = 0;
int vroman = 0;
for (int i = 0; i < strlen(input); ++i)
{
int s1 = value(input[i]);
int s2 = value(input[i]);
if (input[i] == '-')
{
for (int j = i - 1; j >= 0; --j)
{
roman = (roman + value(input[j]));
}
roman *= 1000;
for (int k = i + 1; k <= strlen(input); k++)
roman += value(input[k]);
}
else
roman += s1;
}
return roman;
}
We use '-' instead of the bar on top of the characters, because we cannot do that in computer easily. So IV-, would be 4000 and XI- would be 11,000 etc...
I understand that the way I am doing the loop is causing some numbers that were converted to add twice, because if(input[i] == '-') cycles through each character in the string one at a time.
OK, so my question is basically what is the logic to get it to work? So if the string contains '-' it will multiply the number by 1000, if the string does not contain '-' at ALL, then it will just convert as normal. Right now I believe what is happening is that when "if (input[i] == '-')" is false, that part of the code still runs, how do I not get it to run at all when the string contains '-'??
The posted code seems incomplete or at least has some unused (like end, which if it represents the length of string could be used in place of the following repeated strlen(input)) or meaningless (like s2) variables.
I can't understand the logic behind your "Vinculum" implementation, but the simple
roman += s1; // Where s1 = value(input[i]);
It's clearly not enough to parse a roman number, where the relative position of each symbol is important. Consider e.g. "IV", which is 4 (= 5 - 1), vs. "VI", which is 6 (= 5 + 1).
To parse the "subtractive" notation, you could store a partial result and compare the current digit to the previous one. Something like the following:
#include <stdio.h>
#include <string.h>
int value_of(char ch);
long decimal_from_roman(char const *str, size_t length)
{
long number = 0, partial = 0;
int value = 0, last_value = 0;
for (size_t i = 0; i < length; ++i)
{
if (str[i] == '-')
{
number += partial;
number *= 1000;
partial = 0;
continue;
}
last_value = value;
value = value_of(str[i]);
if (value == 0)
{
fprintf(stderr, "Wrong format.\n");
return 0;
}
if (value > last_value)
{
partial = value - partial;
}
else if (value < last_value)
{
number += partial;
partial = value;
}
else
{
partial += value;
}
}
return number + partial;
}
int main(void)
{
char const *tests[] = {
"I", "L", "XXX", "VI", "IV", "XIV", "XXIII-",
"MCM", "MCMXII", "CCXLVI", "DCCLXXXIX", "MMCDXXI", // 1900, 1912, 246, 789, 2421
"CLX", "CCVII", "MIX", "MLXVI" // 160, 207, 1009, 1066
};
int n_samples = sizeof(tests) / sizeof(*tests);
for (int i = 0; i < n_samples; ++i)
{
long number = decimal_from_roman(tests[i], strlen(tests[i]));
printf("%12ld %s\n", number, tests[i]);
}
return 0;
}
int value_of(char ch)
{
switch (ch)
{
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default:
return 0;
}
}
Note that the previous code only checks for wrong characters, but doesn't discard strings like "MMMMMMMMMMIIIIIIIIIIIIIV". Consider it just a starting point and feel free to improve it.

Capitalizing individual characters in string array

I have to capitalize the first and last name in my string array, but I'm stuck on how to access the specific value after I input my string value into an array.
Here are my two functions, the first one reads the values into two separate arrays, and the second is supposed to capitalize the first and last names while changing all other characters to lower case.
void read(string names[],int DVDrent[],int& n)
{
n=0; // # of data calculated
cin >> names[n] >> DVDrent[n]
while(cin)
{
n++;
cin >> names[n] >> DVDrent[n];
}
}
void reformat(string& names)
{
int nlen;
nlen = names.length();
names[0] = toupper(names[0]);
for (int i=1; i<nlen; i++)
{
if (names[i] == ',')
names[i+1] = toupper(names[i+1]);
names[i+2] = tolower(names[i+2]);
}
}
My second function works if I do simply store my data as a string. I'm stuck right now because I'm not sure how to read the specific characters of my array.
For reference, the data that I enter is as follows.
./a.out < data > output
Data:
smith,EMILY 3
Johnson,Daniel 2
williAMS,HanNAH 0
joneS,Jacob 4
bROwn,MicHAEL 5
DAVIS,ETHAn 2
millER,soPhiA 0
TAYlor,matthew 1
andERSON,aNNa 7
Desired output:
Smith,Emily 3
Johnson,Daniel 2
William,Hannah 0
.
.
.
Anderson,Anna 7
etc.
Try this for your reformat() method:
void reformat(string& names) {
bool isUpper = true; // store if the next letter should be upper
for(size_t i = 0; i < names.length(); ++i) {
if (names[i] == ',') {
isUpper = true; // if it's a comma, make the next letter upper
}
else if (isUpper) {
names[i] = toupper(names[i]);
isUpper = false; // make the next letter lower
}
else {
names[i] = tolower(names[i]);
}
}
}

C++ Accepting a command-line argument with parameters

I've got a program that needs to accept multiple command line arguments. I've gotten to a stage where I need to set it up to accept argument n, which specifies the max and min lengths of the string that will eventually be printed. Basically input could look like this:
-a -n7,7 -i // with -a and -i being other arguments
I'm fine with picking out arguments on their own, but I'm not sure how to pluck out those max and min values too. I've had a go (see below), but whenever I try and use variables minimum and maximum, I just get a run time error. Cheers guys.
int c;
while ((c = getopt(argc, argv, ":wpsaevin")) != -1) {
switch (c) {
case 'w': // pattern matches whole word
mode = WHOLE;
break;
case 'p': // pattern matches prefix
mode = PREFIX;
break;
case 'a': // pattern matches anywhere
mode = ANYWHERE;
break;
case 's': // pattern matches suffix
mode = SUFFIX;
break;
case 'e': // pattern matches anywhere
mode = EMBEDDED;
break;
case 'v': // reverse sense of match
reverse_match = true;
break;
case 'i': // ignore case of pattern
ignore_case = true;
break;
case 'n': //Specifies word length
length_spec = true;
cin >> minimum >> maximum;
if (minimum == 0 && maximum == 0) { //no word limit
length_spec = false;
} else if (maximum == 0) {
maximum = 100;
}
break;
}
}
argc -= optind;
argv += optind;
From this page:
This variable is set by getopt to point at the value of the option
argument, for those options that accept arguments.
case 'n': //Specifies word length
length_spec = true;
char *cvalue = optarg;
// TODO: Split cvalue by delimiter
// to obtain minimum and maximum
if (minimum == 0 && maximum == 0) { //no word limit
length_spec = false;
} else if (maximum == 0) {
maximum = 100;
}
break;
And an example of splitting a string:
#include <iostream>
#include <string>
#include <algorithm>
int
main()
{
const char* test = "1000,2000";
std::string str = std::string(test);
auto find = std::find(str.begin(), str.end(), ',');
std::string first = std::string(str.begin(), find);
std::string second = std::string(find+1,str.end());
std::cout << first << " " << second;
// 1000 2000
}
EDIT
Reference link
If you're able to use C++11, consider using std::stoi, like so:
int first_int = std::stoi( first );
int second_int = std::stoi ( second );
If not, try this:
std::replace(str.begin(), str.end(), ',', ' ');
std::istringstream ss(str);
ss >> first_int;
ss >> second_int;
std::cout << first_int << " " << second_int << std::endl;
I would use atoi as a last resort.
A naive implementation might look like this (use at your own risk):
int convert(std::string s)
{
int size = s.size();
int exp = size - 1;
int result = 0;
for (int i = 0; i < size; i++)
{
char c = s[i];
result += (int)(c - '0') * std::pow(10, exp--);
}
return result;
}
You can use Boost Library Program Options, as #aaronman suggested above.

testing a string to see if a number is present and asigning that value to a variable while skipping all the non-numeric values?

given a string say " a 19 b c d 20", how do I test to see if at that particular position on the string there is a number? (not just the character '1' but the whole number '19' and '20').
char s[80];
strcpy(s,"a 19 b c d 20");
int i=0;
int num=0;
int digit=0;
for (i =0;i<strlen(s);i++){
if ((s[i] <= '9') && (s[i] >= '0')){ //how do i test for the whole integer value not just a digit
//if number then convert to integer
digit = s[i]-48;
num = num*10+digit;
}
if (s[i] == ' '){
break; //is this correct here? do nothing
}
if (s[i] == 'a'){
//copy into a temp char
}
}
These are C solutions:
Are you just trying to parse the numbers out of the string? Then you can just walk the string using strtol().
long num = 0;
char *endptr = NULL;
while (*s) {
num = strtol(s, &endptr, 10);
if (endptr == s) { // Not a number here, move on.
s++;
continue;
}
// Found a number and it is in num. Move to next location.
s = endptr;
// Do something with num.
}
If you have a specific location and number to check for you can still do something similar.
For example: Is '19' at position 10?
int pos = 10;
int value = 19;
if (pos >= strlen(s))
return false;
if (value == strtol(s + pos, &endptr, 10) && endptr != s + pos)
return true;
return false;
Are you trying to parse out the numbers without using any library routines?
Note: I haven't tested this...
int num=0;
int sign=1;
while (*s) {
// This could be done with an if, too.
switch (*s) {
case '-':
sign = -1;
case '+':
s++;
if (*s < '0' || *s > '9') {
sign = 1;
break;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
// Parse number, start with zero.
num = 0;
do {
num = (num * 10) + (*s - '0');
s++;
} while (*s >= '0' && *s <= '9');
num *= sign;
// Restore sign, just in case
sign = 1;
// Do something with num.
break;
default:
// Not a number
s++;
}
}
It seems like you want to parse the string and extract all the numbers from it; if so, here's a more "C++" way to do it:
string s = "a 19 b c d 20"; // your char array will work fine here too
istringstream buffer(s);
string token;
int num;
while (!buffer.eof())
{
buffer >> num; // Try to read a number
if (!buffer.fail()) { // if it doesn't work, failbit is set
cout << num << endl; // It's a number, do what you want here
} else {
buffer.clear(); // wasn't a number, clear the failbit
buffer >> token; // pull out the non-numeric token
}
}
This should print out the following:
19
20
The stream extraction operator pulls out space-delimited tokens automatically, so you're saved from having to do any messy character-level operations or manual integer conversion. You'll need to #include <sstream> for the stringstream class.
You can use atoi().
after your if you need to shift to while to collect subqsequent digits until you hit a non-digit.
BUT, more inportantly, have you clearly defined your requirements? Will you allow whitespace between the digits? What if there are two numbers, like abc123def456gh?
Its not very clear what you are looking for.. Assuming you want to extract all the digits from a string and then from a whole number from the found digits you can try the following:
int i;
unsigned long num=0; // to hold the whole number.
int digit;
for (i =0;i<s[i];i++){
// see if the ith char is a digit..if yes extract consecutive digits
while(isdigit(s[i])) {
num = num * 10 + (s[i] - '0');
i++;
}
}
It is assumed that all the digits in your string when concatenated to from the whole number will not overflow the long data type.
There's no way to test for a whole number. Writing a lexer, as you've done is one way to go. Another would be to try and use the C standard library's strtoul function (or some similar function depending on whether the string has floating point numbers etc).
Your code needs to allow for whitespaces and you can use the C library's isdigit to test if the current character is a digit or not:
vector<int> parse(string const& s) {
vector<int> vi;
for (size_t i = 0; i < s.length();) {
while (::isspace((unsigned char)s[ i ]) i++;
if (::isdigit((unsigned char)s[ i ])) {
int num = s[ i ] - '0';
while (::isdigit((unsigned char)s[ i ])) {
num = num * 10 + (s[ i ] - '0');
++i;
}
vi.push_back(num);
}
....
Another approach will be to use boost::lexical_cast:
vector<string> tokenize(string const& input) {
vector<string> tokens;
size_t off = 0, start = 0;
while ((off = input.find(' ', start)) != string::npos) {
tokens.push_back(input.substr(start, off-start));
start = off + 1;
}
return tokens;
}
vector<int> getint(vector<string> tokens) {
vector<int> vi;
for (vector<string> b = tokens.begin(), e = tokens.end(); b! = e; ++b) {
try
{
tokens.push_back(lexical_cast<short>(*b));
}
catch(bad_lexical_cast &) {}
}
return vi;
}