I was about to write a C++ function doing the following:
1 ---> "1st"
2 ---> "1nd"
3 ---> "3rd"
...
17657 --> "17657th"
...
i.e. produces the ordinal extension string for that number (it doesn't have to do an itoa() of the number itself). But then I thought "surely something in the standard library or boost does this already?"
Notes:
I know it's not hard to write this, there's an implementation in Python right here on SO, I just don't want to duplicate code.
I need this in English, obviously. A multi-language version would be nice for political-correctness considerations, not more than that...
Here's what I ended up writing:
const char* ordinal_suffix(int n)
{
static const char suffixes [][3] = {"th", "st", "nd", "rd"};
auto ord = n % 100;
if (ord / 10 == 1) { ord = 0; }
ord = ord % 10;
if (ord > 3) { ord = 0; }
return suffixes[ord];
}
The code golf solutions are cute, but - they really do optimize for terseness, not anything else. This is faster (although it could be made even faster by putting the suffixes in a .cpp out of the function body and making the code inlinable), much clearer, and still more terse than most other answers here.
// Returns numbers with ordinal suffix as string
// Based on https://stackoverflow.com/questions/3109978/display-numbers-with-ordinal-suffix-in-php
std::string NumberToOrdinal(size_t number) {
std::string suffix = "th";
if (number % 100 < 11 || number % 100 > 13) {
switch (number % 10) {
case 1:
suffix = "st";
break;
case 2:
suffix = "nd";
break;
case 3:
suffix = "rd";
break;
}
}
return std::to_string(number) + suffix;
}
I'm pretty sure you can adapt the four line solution at Display numbers with ordinal suffix in PHP. Unfortunately, I don't think there is such a thing in a common C++ lib.
try this...
#include <iostream>
using namespace std;
void suffix(int n, char suff[]);
// creates the ordinal suffix
// for a given number
int main()
{
char s[5];
int x;
cout << "Enter a number to find the ordinal suffix for ";
cin >> x;
suffix(52111,s);
}
void suffix(int n, char suff[])
{
if(n%100 == 11 || n%100 == 12 || n%100 == 13)
{
cout << "suffix is: " << n << "th";
cout << endl;
}
else
{
if(n%10 == 1)
{
cout << "Suffix is: " << n << "st";
cout << endl;
}
else
{
if(n%10 == 2)
{
cout << "Suffix is: " << n << "nd";
cout << endl;
}
else
{
if(n%10 == 3)
{
cout << "Suffix is: " << n << "rd";
cout << endl;
}
else
{
if(n%10 == 4 || n%10 == 5 || n%10 == 6 || n%10 == 7 || n%10 == 8 || n%10 == 9 || n%10 == 0)
{
cout << "Suffix is: " << n << "th";
cout << endl;
}
}
}
}
}
}
I used the following string function to accomplish it.
#include <string>
#include <iostream>
using namespace std;
string ordinal(int i)
{
if(i==1)
{
return "First";
}
if(i==2)
{
return "Second";
}
if(i==3)
{
return "Third";
}
if(i==4)
{
return "Fourth";
}
if(i==5)
{
return "Fifth";
}
if(i==6)
{
return "Sixth";
}
if(i==7)
{
return "Seventh";
}
if(i==8)
{
return "Eighth";
}
}
int main()
{
for(int i=0; i<8; i++)
{
cout << ordinal(i+1) << " number: ";
}
return 0;
}
#include <iostream>
#include <string>
std::string number_to_ordinal(int number)
{
// Convert number to string
std::string ordinal = std::to_string(number);
// Get the last character of the number to later determine ordinal indicator
char last_char = ordinal.back();
// Get the last two characters of the number to deal with ordinal indicator conditions
std::string last_two_char;
if(ordinal.size() > 1)
last_two_char = ordinal.substr(ordinal.size() - 2, ordinal.size());
// Determine ordinal indicator. Each number with a last character ending in '1', '2',
// and '3' require ordinal indicators of 'st', 'nd', and 'rd', respectively. However,
// numbers with the last two characters ending in '11', '12', and '13' require 'th'
// as the ordinal indicator.
if(last_two_char != "11" && last_char == '1')
ordinal += "st";
else if (last_two_char != "12" && last_char == '2')
ordinal += "nd";
else if (last_two_char != "13" && last_char == '3')
ordinal +="rd";
else
ordinal += "th"; // All other numbers require 'th' as the ordinal indicator
return ordinal;
}
///////////////////////////////////////////////////////////////////////
// Main Program
///////////////////////////////////////////////////////////////////////
int main()
{
// Test number to ordinal
for(int i = 17657; i < 17725; i++)
std::cout << number_to_ordinal(i) << std::endl;
return 0;
}
Related
I'm quite new to C++, so I apologize if I am not sounding technical. I am having a little trouble getting a multiple input and output with my code, I'm thinking I should have a loop to get the data but i'm not sure how i'd go about that in my code, I've thought about using getline() but that doesn't seem to want to work with Char.
I've tried getline but I'm not sure how to implement it with the Char input, I believe I may need a separate loop as well but again not too sure. I'm thinking it could be done to EoF as well.
Here's my code:
int main()
{
char inpval;
int outval = 0;
cout << "Enter a Roman Number to convert: " << endl;
while (cin.get(inpval))
{
inpval = toupper(inpval);
if (inpval == 'M')
outval = outval + 1000;
else if (inpval == 'D') {
inpval = cin.peek();
inpval = toupper(inpval);
if (inpval == 'M') {
outval = outval - 500;
continue;
} else {
outval = outval + 500;
continue;
}
}
//etc
cout << "The Equivalent Arabic value is:" << endl;
cout << outval << "\n";
return 0;
}
My expected output is:
(All on newline)
Input:
I
II
IV
V
VI
Output:
1
2
4
5
6
Actual output is:
Input:
I
Output:
1
P.S: The program converts Roman Numeral chars to their respected number.
Any help is appreciated!
You can take input multiple items from cin, using below syntax.
cin >> a;
cin >> b;
cin >> c;
Another way is also there
cin >> a >> b >> c;
This technique is called "operator chaining" which is similar to the above.
Do you have any problem doing it like this?
cout << "Enter a Roman Numeral" << endl;
string inpval;
cin >> inpval;
while (inpval != "exit")
{
int outval = 0;
if (inpval == "I")
outval = 1;
else if (inpval == "II")
outval = 2;
else if (inpval == "III")
outval = 3;
else if (inpval == "IV")
outval = 4;
// ect
cout << "The Equivalent Arabic value is: " << outval << endl << endl;
cout << "Enter next numeral: (type exit to exit) " << endl;
cin >> inpval;
}
Method 1: Use getchar(), Calculate/Convert Roman to integer until you encounter a space ' ',when you get a space ' ' output the integer and do the same next roman number until you get another space ' ' or newline '\n' and stop the program once you encounter newline '\n'.
Method 2:Use type std::string and take input with getline. Then iterate through the string and calculate until you find space ' ' output the number, do the same till you find next space ' ' or end when string ends.
If you know # of Roman numbers you want to convert you can put it in a loop.
Hope this helps.
Example(Method 2)
#include <bits/stdc++.h>
int value(char r)
{
if (r == 'I')
return 1;
if (r == 'V')
return 5;
if (r == 'X')
return 10;
if (r == 'L')
return 50;
if (r == 'C')
return 100;
if (r == 'D')
return 500;
if (r == 'M')
return 1000;
return -1;
}
int main()
{
int out=0;
std::string s;
std::string::iterator i; //string iterator
//for more info go to https://www.geeksforgeeks.org/stdstring-class-in-c/
getline(std::cin,s);
for (i = s.begin(); i!= s.end() ; ++i)
{
if(*i != ' ')//Encounter a space, output result and
{ //go to next roman numeral
int s1 = value(*i);
if (*(i+1) != ' ' || *(i+1) != '\0')
{
// Getting value of i+1 nth Element
int s2 = value(*(i+1));
// Comparing both values
if (s1 >= s2)
{
// Value of current symbol is greater
// or equal to the next symbol
out = out + s1;
}
else
{
out = out + s2 - s1;
i++; // Value of current symbol is
// less than the next symbol
}
}
else
{
out = out + s1;
i++;
}
}
else
{
std::cout<<out<<" ";
out = 0;
}
}
std::cout<<out<<" ";
std::cout<<std::endl;
return 0;
}
Input:
I II MM MCMIV
Output:
1 2 2000 1904
The program takes in a word given by the user and translates that to pig latin. I've gotten everything to work almost perfectly, but have run into two bugs. The first of which is when translating words that begin with consonants say "count", the output is "ounttcay" instead of "ountcay". The second bug is that when for three letter words like "egg" or "not" the output is "egg_\377ay" or "ottn\377ay". Is there a simple way to remove that duplicate character and get rid of those numbers?
Note - Unfortunately it has to be done using a Cstring
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
int convertToPigLatin(char arr[50]);
bool isVowel(char ch);
int main() {
char userInput[50];
char answer = ' ';
do {
cout << "Enter a word to convert it to pig latin" << endl;
cin.getline(userInput, 50); //get user input
cout << "Your entered word is " << userInput << endl;
convertToPigLatin(userInput); //translate user's input into piglatin
cout << "Would you like to convert another word?" << endl;
cin >> answer;
cin.ignore(); //clear past user input
cin.clear();
} while (answer == 'Y' || answer == 'y');
return 0;
}
bool isVowel (char ch) {
switch (tolower(ch)) { //if the first character of the given input is a vowel
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
default:
return false;
}
}
int convertToPigLatin(char arr[50]) {
char newArr[50];
// string conjunctions[6] = {"and","but","for","nor","yet","the"}; //list of conjunctions not to be converted
size_t arrLength = strlen(arr); //holds length of input
for (int i = 0; i < arrLength; i++) { //make sure all characters in input are lower case for easier processing
newArr[i] = tolower(arr[i]);
}
char lastChar = newArr[0]; //save the first character in case it needs to be appended
if (atoi(arr) || arr[0] == '\0') { //if the input contains a number or begins with a null character print an error
cout << "Cannot translate inputs that contain numbers" << endl;
return -1;
} else if (arrLength <= 2) { // if the input is 2 or less characters
cout << newArr << endl; //print the input as is
cout << "Boring! Try somthing more than 2 characters long" << endl;
return 0;
} else if ((strstr(newArr, "and") && arrLength == 3) || (arrLength == 3 && strstr(newArr, "but")) || (arrLength == 3 && strstr(newArr, "for")) || (arrLength == 3 && strstr(newArr, "nor")) || (arrLength == 3 && strstr(newArr, "yet")) || (arrLength == 3 && strstr(newArr, "the"))) { //if the input is more than 2 characters long
cout << newArr << endl; //print the input as is
cout << "No conjucntions try again!" << endl;
return 0;
} else { //if the given input is three characters and is not a conjunction, being translation
if (isVowel(arr[0])) { //check if input's first character is a vowel
cout << "Your word in piglatin is "<< strcat(newArr, "ay") << endl; //print that string with 'ay' at the end (i.e. egg'ay')
return 0;
} else { //else if the given input starts with a consonant
for (int r = 1; r < arrLength; r++) {
newArr[r-1] = newArr[r];
newArr[arrLength] = lastChar;
}
cout << "Your word in piglatin is " << strcat(newArr, "ay") << endl;
return 0;
}
}
return 0;
}
You're not terminating newArr, and the last index of the input string is arrLength - 1.
int convertToPigLatin(char arr[50]) {
// Make sure newArr is properly terminated.
char newArr[50] = {0};
// [...]
} else { //else if the given input starts with a consonant
for (int r = 1; r < arrLength; r++) {
newArr[r-1] = newArr[r];
}
// Do this outside the loop.
newArr[arrLength-1] = lastChar;
// No need for strcat here.
cout << "Your word in piglatin is " << newArr << "ay" << endl;
}
}
return 0;
}
You need to add the '\0' at the end of newArr because strlen does not count it so you are not copying it. strcat replaces '\0' witn 'ay\0' but you have no '\0'.
for (int r = 1; r < arrLength; r++) {
newArr[r-1] = newArr[r];
newArr[arrLength] = lastChar;
}
newArr[arrLength+1] = '\0';
cout << "Your word in piglatin is " << strcat(newArr, "ay") << endl;
From what I am reading from the book and from prior examples that I have been doing from the book this is what I have come up with. I appreciate the extra advice but I am trying to learn what the chapter is trying to show me so I can move on and learn the basics before I try code I have never seen before. I want the user to type 0 to end the loop but for some reason the loop keeps going? I think I may be missing something that is preventing it from stopping.
// Ex4_08.cpp
// Initializing pointers with strings
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
bool keepgoing = true;
int answer;
while (keepgoing = true)
{
const char* pstr[]{ "Aa", // Initializing a pointer array
"Bb",
"Cc",
"Dd",
"Ee",
"Ff",
"Gg",
"Hh",
"Ii",
"Jj",
"Kk",
"Ll",
"Mm",
"Oo",
"Pp",
"Qq",
"Rr",
"Ss",
"Tt",
"Uu",
"Vv",
"Ww",
"Ss",
"Yy",
"Zz",
};
const char* pstart{ "Your letter is " };
int dice{};
cout << endl
<< "Enter a number between 1 and 26 " << _countof(pstr) << ": ";
cin >> dice;
cout << endl;
if (dice >= 1 && dice <= _countof(pstr)) // Check input validity
cout << pstart << pstr[dice - 1]; // Output star name
else
cout << "Sorry, you haven't selected a correct number."; // Invalid input
cout << "Do you want to do this again? Type 0 for no: " << endl;
cin >> answer;
if (answer == 0)
{
keepgoing = false;
}
}
cout << endl;
return 0;
}
I've modified you initial code sample, using vector and string which are more C++ and easier to use:
#include <iostream>
#include <string> // for string
#include <vector> // for vector
using std::cin;
using std::cout;
using std::endl;
int main()
{
std::vector<std::string> pstr;
for (char c = 'a'; c <= 'z'; c++) // cycle over the 26 ASCII letters
{
std::string temp; //
temp += c - 32; // add capital character (e.g A)
temp += c; // add character (e.g. a)
pstr.push_back(temp); // push the new string (e.g. Aa) to the vector
}
const char* pstart{ "Your letter is " };
int dice{};
while (true)
{
cout << endl
<< "Enter a number between 1 and 26 " << pstr.size() << ": ";
cin >> dice;
if (dice == 0)
{
break; //break if the user enters 0
}
cout << endl;
if (dice >= 1 && dice <= pstr.size()) // Check input validity
cout << pstart << pstr[dice - 1]; // Output star name
else
cout << "Sorry, you haven't selected a correct number."; // Invalid input
}
cout << endl;
return 0;
}
Your code is wrong here:
while (keepgoing = true) {
...
if (answer == 0) {
keepgoing = false;
}
}
You are setting the keepgoing to false, but in the while condition you are resenting it to true. You must use the == operator (as in while(keepgoing == true)) or remove it (while(keepgoing)).
Otherwise, you may use while(true) or for (;;) and break instead of keepgoing = false:
for (;;) { // or while (true); to me, that's only a matter of preference.
...
if (answer == 0) {
break; // exit the loop
}
}
They do produce infinite loop until you enter the break condition.
Change this line:
while (keepgoing = true)
To this:
while (keepgoing == true)
The first assigns the value true to the variable keepgoing. The second checks of the value of keepgoing is true. This is a very common issue that trips of many new programmers (and occasionally an old one). :-)
How can I output an "error" message if the input is not a letter from a to z or a digit from 1 to 9.
For exemple, if the user inputs '%', how can I output "error" ?
I tried this :
if ((name.letter <= a) && (name.letter >= z)) {
cout << "error";
}
but I guess it's just not C++ code...
There are useful functions in standard library cctype.
example:
#include <cctype>
if (!islower((unsigned char)name.letter) && (!isdigit((unsigned char)name.letter) || name.letter == '0')) {
cout << "error";
}
If the type of name is std::string, it may be like this:
#include <iostream>
#include <string>
#include <cctype>
using std::cout;
int main(void) {
std::string name = "1%";
// use loop to check every characters
bool valid = true;
for (size_t i = 0, len = name.length(); i < len; i++) {
unsigned char c = (unsigned char)name[i];
if (!islower(c) && (!isdigit(c) || name[i] == '0')) {
// illegal character is found
valid = false;
break;
}
}
if (!valid) {
cout << "error";
}
return 0;
}
You could easily check your conditions with a few things that already exist in the standard library (<cctype>). Namely:
isdigit - Checks whether a character is a decimal digit character.
isalpha - Checks whether a character is an alphabetic letter.
These both take int arguments, but you could do something like the following:
char c;
cin >> c;
if(!(isdigit(c) && c != '0') && !isalpha(c)) {
std::cerr << "Error!\n";
}
Note that isalpha will return true if c is a letter - this means uppercase or lowercase. If you really need one or the other, you could use islower or isupper.
Since name is a std::string, you could do the following:
for(auto c: name) {
if(!(isdigit(c) && c != '0') && !isalpha(c)) {
std::cerr << "Error: " << c << " is not a valid character\n";
break; // or return or exit
}
}
How can I output an "error" message
You have marked this post as C++.
One C++ way to handle this is:
void checkName(std::string name)
{
const std::string letters = "abcdefghijklmnopqrstuvwxyz";
const std::string digits = "123456789";
const std::string letterDigits (letters + digits);
std::cout << "\nname '" << name << "'" << std::endl;
size_t indx = name.find_first_not_of(letterDigits);
if(indx != std::string::npos)
{
std::cerr << "error at indx " << indx << " == '" << name[indx] << "'\n" << std::endl;
}
else
{
std::cout << "all chars of name '" << name << "' are letters or digits\n" << std::endl;
}
}
int main(int /*argc*/, char** /*argv*/ )
{
{
std::string name = "dan%iel";
checkName(name);
}
{
std::string name = "daniel";
checkName(name);
}
return (0);
}
Not with a switch statement! Just enclose the letters in single quotation marks, so they are treated as their ASCII values:
if ((name.letter <= 'a') && (name.letter >= 'z')) {
cout << "error";
}
Switch statements can only be used to match specific cases you specify, not ranges of cases as in some other languages.
I am trying to write a c++ program that validates a password that requires one uppercase letter, one lowercase letter, and a digit using functions.
The issue is that I'm trying to display the specific errors that are occurring, not just "Invalid, try again.", but I'm having a hard time figuring out how to do that. It should keep asking until they enter a valid password.
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int validate(string);
string find(int);
int main()
{
string pw;
int val;
string result;
do{
cout << "Enter password: " << endl;
cin >> pw;
val = validate(pw);
cout << find(val) << endl;
} while (val != 0);
}
//VALIDATES PASSWORD
int validate(string pw)
{
int valid = 0;
char c;
int length = pw.length();
bool digit = false;
bool upper = false;
bool lower = false;
int i = 0;
if (pw.length() < 6)
valid = 1;
while (i < pw.length())
{
c = pw[i];
i++;
if (isdigit(c))
{
digit = true;
valid++;
}
if (isupper(c))
{
upper = true;
valid++;
}
if (islower(c))
{
lower = true;
valid++;
}
//Valid input
if (length >= 6 && upper && lower && digit)
valid = 0;
}
return valid;
}
//RETURNS STRING WITH PROBLEM
string find(int valid)
{
string result;
if (valid == 0)
{
result = "Valid Password ";
}
else
{
result = "Invalid Password: ";
if (valid == 1)
result = result + " Too short ";
else if (valid == 2)
result = result + " too short, needs a digit, and an uppercase letter";
else if (valid == 3)
result = result + " too short, needs a digit, and a lowercase letter";
else if (valid == 4)
result = result + " too short, and needs an uppercase letter";
else if (valid == 5)
result = result + " too short, and needs a lowercase letter";
else if (valid == 6)
result = result + " too short, needs a digit";
else if (valid == 7)
result = result + " Needs a didgit ";
else if (valid == 8)
result = result + " Needs digit and uppercase letter ";
else if (valid == 9)
result = result + " Needs digit and lowercase letter";
else if (valid == 10)
result = result + " Needs an uppercase letter ";
else if (valid == 11)
result = result + " Needs uppercase and lowercase letter";
else if (valid == 12)
result = result + " Needs a lowercase letter";
}
return result;
}
I think you are confusing the number of characters (valid) and the type of error -
else if (valid == 9)
result = result + " Needs digit and lowercase letter";
could be produced from 123456abc
As valid == 9 really only counts the characters in the set. Separate counting and whether character classes are used.
It's better to use some flags (bool variables) instead of one number.
If you want to use one number, you must create 2^(things to check) situations
using that number. Here 2^4 = 16 situations is required.
One of the easiest way to mix flags in one number is this:
nth digit = nth flag
for example use this order (length, lower, upper, digit).
So,
to set length validity, add 1000 to number;
to set lower validity, add 100 to number;
to set upper validity, add 10 to number;
to set digit validity, add 1 to number;
Now,
((number)%10 == 1) means digit validity
((number/10)%10 == 1) means upper validity
((number/100)%10 == 1) means lower validity
((number/1000)%10 == 1) means length validity
Following code uses separate flags:
#include<iostream>
#include<string>
using namespace std;
class PasswordStatus
{
bool len, low, up, dig;
//============
public:
PasswordStatus()
{
len = low = up = dig = false;
}
//-----------
void ShowStatus()
{
cout << endl << "Password Status:" << endl;
cout << "Length : " << (len ? "OK" : "Too Short") << endl;
cout << "Contains Lower Case : " << (low ? "Yes" : "No") << endl;
cout << "Contains Upper Case : " << (up ? "Yes" : "No") << endl;
cout << "Contains Digit : " << (dig ? "Yes" : "No") << endl;
}
//-----------
void checkValidity(string pass)
{
int sLen = pass.length();
len = (sLen >= 6);
for(int i = 0; i<sLen; i++)
{
char c = pass[i];
if(!low && islower(c)) {low = true; continue;}
if(!up && isupper(c)) {up = true; continue;}
if(!dig && isdigit(c)) {dig = true; continue;}
}
}
//-----------
bool IsTotalyValid()
{
return low && up && dig && len;
}
};
//====================================================================
int main()
{
PasswordStatus ps;
string pw;
do
{
cout << endl << "Enter password: " << endl;
cin >> pw;
ps.checkValidity(pw);
ps.ShowStatus();
} while (!ps.IsTotalyValid());
cout << "Valid Password : " << pw;
return 0;
}