C++ Accepting a command-line argument with parameters - c++

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.

Related

Basic program to convert Roman number Arabic form?

I am wanting some help in answering these two questions. The first one is this:
I am trying to write a program that converts a single Roman number in the range I (1) to IX (9) to Arabic form. The
program should read a single string from standard input and print the corresponding value to standard output.
I then want to Extend the program so that it works correctly when the input consists of either lower case or upper case Roman letters.
The simplest approach is to convert each character in the input word into uppercase before trying to find a match. Run a
loop over the characters in the string using the index operator ([]) to access each character and use the toupper
function (you will need to include the cctype header file) to get the corresponding uppercase value.
For the second question this is what it wants me to do next:
Extend the program so that it can deal with single digit numbers of any value. A single digit number is one that consists
only of thousands, hundreds, tens, or units. Thus LXX (70) and CD (400) are single digit numbers, but XIV (14) and
MC (1100) are not. Use the same approach as for units digits, but with 4 different arrays, one each for the thousands,
hundreds, tens, and units digits. Try looking for thousands digits first, then for hundreds, and so on. When you find a
match in one of the arrays, print the corresponding value and stop.
Modify the program so that it reads and converts all input numbers until end of file (eof) on standard input. You will
probably be able to do this by simply adding an appropriate reading loop around the code that reads a single line.
Currently this is what i have to start but am unsure how to write a program like this:
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;
class RomanNumeral
{
public:
const static int M = 1000;
const static int D = 500;
const static int C = 100;
const static int L = 50;
const static int X = 10;
const static int V = 5;
const static int I = 1;
RomanNumeral( const int arabic ) :
m_roman( "" ),
m_arabic( ((arabic > 0) ? arabic : 0) )
{
if( arabic > 0 )
{
int i = arabic;
while( i > 0 )
{
if( ( i - M ) >= 0 )
{
m_roman += "M";
i -= M;
continue;
}
if( ( i - D ) >= 0 )
{
m_roman += "D";
i -= D;
continue;
}
if( ( i - C ) >= 0 )
{
m_roman += "C";
i -= C;
continue;
}
if( ( i - L ) >= 0 )
{
m_roman += "L";
i -= L;
continue;
}
if( ( i - X ) >= 0 )
{
m_roman += "X";
i -= X;
continue;
}
if( ( i - V ) >= 0 )
{
m_roman += "V";
i -= V;
continue;
}
if( ( i - I ) >= 0 )
{
m_roman += "I";
i -= I;
continue;
}
}
}
else
{
m_roman = "0";
}
}
RomanNumeral( const std::string& string ) :
m_roman( ((string.size() > 0 ) ? string : "0" ) ),
m_arabic( 0 )
{
int i = 0;
while( i < (int)string.size() )
{
char c = string[i++];
switch( c )
{
case 'M':
case 'm':
m_arabic += M;
break;
case 'D':
case 'd':
m_arabic += D;
break;
case 'C':
case 'c':
m_arabic += C;
break;
case 'L':
case 'l':
m_arabic += L;
break;
case 'X':
case 'x':
m_arabic += X;
break;
case 'V':
case 'v':
m_arabic += V;
break;
case 'I':
case 'i':
m_arabic += I;
break;
default:
throw new std::out_of_range( "Not a valid Roman numeral!" );
break;
}
}
}
int getArabic()
{
return m_arabic;
}
void setArabic( const int arabic );
const std::string& getRoman()
{
return m_roman;
}
protected:
std::string m_roman;
int m_arabic;
};
int main()
{
std::string roman;
cin >> roman;
try
{
RomanNumeral rn( roman );
cout << rn.getArabic() << endl;
}
catch( exception* ex )
{
cout << roman << " " << ex->what() << endl;
}
return 0;
}
Have been doing some tutorials on it but came across this question on a website the other day but I can't find the solution to this to see how its done. Could you demonstrate how to write a program like this by any chance?
Whenever you're stuck on a problem, try to decompose it into steps and implementing the things you can.
Step one is reading a single word:
std::string word;
std::cin >> word;
Step two is converting the word into a number:
int convert_to_number(const std::string& w) {
if (w == "I") return 1;
if (w == "II") return 2;
// and so on.
}
Step three is doing the conversion and printing the result:
std::cout << convert_to_number(word) << std::endl;
Instead of writing large amounts of if statements, you may want to try using an std::map<std::string, int> or std::unordered_hash<std::string, int> for a constant-time lookup.

While Loop in For Loop

I'm trying to count the cats and dogs in a string. So,
for example:
if the string is "cc+dd-cd",:
I want to count 2 positive cats, 2 positive dogs, 1 negative cat, 1 negative dog (yes I know this is a weird way to count, but it's part of my assignment).
I thought about doing a for loop where I iterated over the string, then nested inside the for loop, I'd have a while loop that would run until a '-', then run until a '+' or the end. I started the code, and without even getting that far into it, it created an infinite loop.
Question: How can I fix it?
Thanks!
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
while (k != '-'){
pdc = pdc + 1; //positive dog count
pcc = pcc + 1; //positive cat count
}
while (k != '+') {
ndc = ndc + 1;
ncc = ncc + 1;
}
}
The immediate issue is that the while loops check k's value, but don't modify it. So once you entered one of them you'll be stuck there infinitely as k doesn't change inside the loop's body.
I wouldn't bother with nested loops - I'd just go over the entire string in one loop, and evaluate each character in its turn. A neat way to accomplish this is to keep a state of whether you're adding or subtracting (according to whether you last encountered a + or a - sign:
bool positive = true;
string animalparkString = "cc+dd-cd";
for (int k = 0; k < animalparkString.size(); k++) {
char ch = animalparkString[k];
switch (ch) {
case '+':
positive = true;
break;
case '-':
positive = false;
break;
case 'c':
if (positive) {
pcc++;
} else {
ncc++
}
break;
case 'd':
if (positive) {
pdc++;
} else {
ndc++
}
break;
}
}
This post describes iterating all characters is a string.
This is a simple solution using modern C++:
int sign = 1;
int dogs_count = 0, cats_count = 0;
std::string animalparkString = "-cccccc+dddd-cd";
for (const char& ch : animalparkString)
{
switch (ch) {
case '+':
sign = 1;
continue;
case '-':
sign = -1;
continue;
case 'c':
cats_count += sign;
continue;
case 'd':
dogs_count += sign;
continue;
}
}
std::cout <<"dogs: " << dogs_count << " cats: " <<cats_count;
A couple of suggestions to help you get started:
1. Use online c++ compilers to quickly test code
2. If your code doesn't behave as expected, use step-by-step debugging in your IDE or print our variables as you go using std::cout
3. Explicitly stating namespace is considered good practice. i.e:
// preferable:
std::string myString;
// avoid:
using namespace std;
string myString
To make your code work without too many changes , you can simply replace the while() condition with an if(). Moreover, instead of checking the iterator value k, you should compare the kth string element animalparkString[k].
Then you might start wondering if the code you wrote is actually doing what you expect. Possible questions you could try to answer is "how do I distinguish between positive or negative counts" and, then, "how do I distinguish between cats and dogs "? You will probably need to check also for cs and ds, not only for the operation sign!
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
if(animalparkStrink[k] != '-'){
// Now you know, there will be a pos count. Dog or Cat?
}
if(animalparkString[k] != '+') {
// Now you know, there will be a neg count. Dog or Cat?
}
}
Note that if you write while( k != '-'), it will always evaluate true and, therefore, you will be stuck there. If it is the first time working with for-loops, consider printing the iterator value, to understand when and where you are stuck.
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
std::cout << "for-loop iteration number: " << k << std::endl;
if(animalparkStrink[k] != '-'){
// Now you know, there will be a pos count. Dog or Cat?
}
if(animalparkString[k] != '+') {
// Now you know, there will be a neg count. Dog or Cat?
}
}
for and while together approach is unnecessarily complicated. Here's a simpler solution:
#include <concepts>
#include <iostream>
int main() {
auto const& str{"cc+dd-cd"};
std::boolean auto isPositive = 1;
std::integral auto pdc{0}, pcc{0}, ndc{0}, ncc{0};
for (char const ch : str) {
switch (ch) {
case 'c': {
pcc += isPositive;
ncc += !isPositive;
break;
}
case 'd': {
pdc += isPositive;
ndc += !isPositive;
break;
}
case '+': {
isPositive = true;
break;
}
case '-': {
isPositive = false;
break;
}
}
}
std::cout << "pcc: " << pcc << '\n'
<< "ncc: " << ncc << '\n'
<< "pdc: " << pdc << '\n'
<< "ndc: " << ndc << '\n';
}
LIVE

C++ read number string and capture specific position character as int

I need my program to read a string of numbers input by the user and then assign each number to an int variable:
94715 is input by the user as string
then
a=9
b=4
c=7
d=1
e=5
so I can
if (a < b), c*d+e, a-e, etc
I've searched some commands (getline, string.substr(ind,n), getc, fgetc, atoi, etc) I know I'm close but I can't find examples of exactly what I'm looking for.
The simplest and most direct way I've found is
stringstream convert(string1);
convert>>variable;
but it converts the whole string, if there was a way to add an ind position in it like
string1.substr(0,1)
that'd do the trick...
It is as simple as this:
std::string num = "94715";
size_t i = 0;
assert( num.length() > 4 );
int a = num[i++] - '0';
int b = num[i++] - '0';
int c = num[i++] - '0';
int d = num[i++] - '0';
int e = num[i++] - '0';
note: this may not work properly on systems not using ACII encoding, but it is unlikely you would hit such problem.
int number = 9544;
int vector[10]; // you can make it as big as you want or simply use std::vector
int position = 0;
while (number != 0)
{
vector[position++] = number % 10; // this assigns the last digit
number = number / 10; // remove the last digit
}
for(int i=0; i<position; i++)
std::cout << vector[i]; // this will print 4459
Now you have your number's digits inside an int vector.
This example uses chars because a string is still a char array.
This is for if you are on Windows. Just input and press the enter key.
Like Dieter Lücking suggested, it does this character by character.
It uses kbhit() and getch() found in conio.h to process single characters.
Then it multiplys the characters with appropiate position to get full integer.
And then it stores them in the array digitArray[ ], and assigns them to a,b,c,d or e after. Now you can do whatever with a,b,c,d and e.
Here is some code to demonstrate.
// Re: Now it is just clunky
// one ten hundred thousand
// 1 2 3 4
//digitn=digitArray[3]*1 + digitArray[2]*10 +digitArray[1]*100 +digitArray[0]*1000
#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int digit=0,digitInput=0;
int digitArray[10]={0},digitn;
int numberOfInputDigits=7;
void SplitIntoDigits(void);
int a=0,b=0,c=0,d=0,e=0,f=0;
int main(){
system("color 1F"); //Blue background
while(1){
cout<<"\nPlease enter number. Max Input is "<<numberOfInputDigits<<" individual digits \n";
cout<<"or press enter when done \n>" ;
memset(digitArray,0,sizeof(digitArray));
a=0;b=0;c=0;d=0;e=0;f=0;
SplitIntoDigits();
//cout<<"\n"<<digitArray[7]="<<digitArray[7];
cout<<"\n\n";
a = digitArray[0];
b = digitArray[1];
c = digitArray[2];
d = digitArray[3];
e = digitArray[4];
f = digitArray[5];
cout<<"a = "<< a <<"\n";
cout<<"b = "<< b <<"\n";
cout<<"c = "<< c <<"\n";
cout<<"d = "<< d <<"\n";
cout<<"e = "<< e <<"\n";
cout<<"f = "<< f <<"\n";
cout<<"\n\n The whole combined int number is "<<digitn<<"\n\n";
}
return 0;
}
/*********************************
* *
********************************/
void SplitIntoDigits(void){
digitArray[0]=0;
digitArray[1]=0;
digit=0;
digitInput=0;
while((digit<numberOfInputDigits)){
if (kbhit()){
digitInput=getch();
if (digitInput==27) exit(0);
if ((digitInput>47) && (digitInput<59)) {
digitArray[digit]=(unsigned char)digitInput-48;
digit++;
cout<<digitInput-48;
}
if (digitInput==13) { digitn=digitArray[0]; break; }
}
}
switch(digit) {
case 0:
case 1:
digitn=digitArray[0]*1 ;
break;
case 2:
digitn= digitArray[1]*1 +digitArray[0]*10 ;
break;
case 3:
digitn= digitArray[2]*1+digitArray[1]*10 +digitArray[0]*100 ;
break;
case 4:
digitn=digitArray[3]*1+digitArray[2]*10+digitArray[1]*100+digitArray[0]*1000 ;
break;
case 5:
digitn=digitArray[4]*1+digitArray[3]*10+digitArray[2]*100+digitArray[1]*1000+digitArray[0]*10000 ;
break;
case 6:
digitn=digitArray[5]*1+digitArray[4]*10+digitArray[3]*100+digitArray[2]*1000+digitArray[1]*10000
+digitArray[0]*100000;
break;
case 7:
digitn=digitArray[6]*1+digitArray[5]*10+digitArray[4]*100+digitArray[3]*1000+digitArray[2]*10000
+digitArray[1]*100000 +digitArray[0]*1000000;
break;
case 8:
digitn=digitArray[7]*1+digitArray[6]*10+digitArray[5]*100+digitArray[4]*1000+digitArray[3]*10000
+digitArray[2]*100000 +digitArray[1]*1000000+digitArray[0]*10000000;
break;
case 9:
digitn=digitArray[8]*1+digitArray[7]*10+digitArray[6]*100+digitArray[5]*1000+digitArray[4]*10000
+digitArray[3]*100000 +digitArray[2]*1000000+digitArray[1]*10000000 +digitArray[0]*100000000;
break;
}
// if (digitInput!=13) digitn=digitArray[3]*1+digitArray[2]*10+digitArray[1]*100+digitArray[0]*1000 ;
//cout<<("\n%i\n\n",digitn);
}
/*********************************
* *
********************************/

String manipulation with permutation

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)));
}

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;
}