I'm trying to use something like strcmp to compare a command like "Hello 4" and keep the 4 as a variable
Something like this:
if(strcmp(c, "Hello %d") == 0){
int num = %d;
}
You're looking for sscanf, which uses the scanf-style percent encoders you're using and takes a string to parse as its argument (as well as pointers to store the successful parses into).
It returns the number of arguments successfully stored, or a negative number in the case of an EOF error. In your case, we'll consider it a successful parse if we successfully store the one argument. If we get a zero, that's a failed parse, and if we get a negative number, that's a premature EOF, so we want the result of sscanf to be greater than zero.
#include <cstdio>
#include <iostream>
int main() {
const char* c = "Hello 100";
int num;
if (std::sscanf(c, "Hello %d", &num) > 0) {
std::cout << "Success! " << num << std::endl;
} else {
std::cout << "Failure..." << std::endl;
}
}
Note that in the else branch, the num variable won't be assigned, so it will have whatever value your code previously assigned to it (which, in the code sample I've shown here, is nothing at all, hence UB). So be careful not to reference that variable in the failure branch.
Regular expressions are a way to solve this if you're using C++ and not simply compiling C with a C++ compiler.
#include <iostream>
#include <string>
#include <regex>
int main() {
std::string foo = "hello 4";
std::smatch matches;
if (std::regex_match(foo, matches, std::regex("hello (\\d+)"))) {
std::cout << matches[1] << std::endl;
}
return 0;
}
Using regular expressions makes it trivial to account for varying formatting of the string. E.g. What if there are spaces before or after the items we're looking for?
std::regex("\\s*hello\\s+(\\d+)\\s*")
Or maybe we want to do that but also make it case-insensitive.
std::regex("\\s*hello\\s+(\\d+)\\s*",
std::regex_constants::icase)
Related
int main()
{
char hmm[1000];
cin.getline(hmm, 1000);
cout << hmm << endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!isdigit(hmm[sayac])) {
if (islower(hmm[sayac]))
cout << toupper(hmm[sayac]);
else if (isupper(hmm[sayac]))
cout << tolower(hmm[sayac]);
else
cout << hmm[sayac];
}
}
"Write a program that reads keyboard input to the # symbol and that echoes the input
except for digits, converting each uppercase character to lowercase, and vice versa.
(Don’t forget the cctype family.) "
I'm doing this exercise from the primer book. But when I run it, it returns the ascii order of the char, not the uppercase/lowercase version of the character. Couldn't figure out the problem. Can someone tell my why please?
(I may have other problems about the exercise, please don't correct them if I have. I want to fix it on my own (except the problem I explained), but I can't check the other ones as I have this problem.
When writing
std::cout << toupper('a');
the following happen:
int toupper(int ch) is called, and returns an integer whose value is 'A' (0x41).
std::basic_ostream::operator<<(std::cout, 0x41) is called, that is the int (2) overload since an int was provided.
Overall, it prints "65".
As a solution, you can cast back your upper case to a char:
std::cout << static_cast<char>(toupper('a'));
It's a question of representation. There is no difference between a character and that character's numeric value. It's all in how you choose to display it. For example, the character 'a' is just a constant with a value equal to the character's numeric value.
The problem you are having is that std::toupper and std::tolower return an int rather than a char. One reason for that is that they handle EOF values, which are not necessarily representable by char. As a consequence, std::cout see you are trying to print an int and not a char. The standard behavior for streaming an int is to print the number. The solution is then to cast your result to char to force the value to be interpreted as a character. You can use something like std::cout << static_cast<char>(std::toupper(hmm[sayac]));.
Try the following :
#include <cctype>
#include <iostream>
int main()
{
char hmm[1000];
std::cin.getline(hmm, 1000);
std::cout << hmm << std::endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!std::isdigit(hmm[sayac])) {
if (std::islower(hmm[sayac]))
std::cout << static_cast<char>(std::toupper(hmm[sayac]));
else if (isupper(hmm[sayac]))
std::cout << static_cast<char>(std::tolower(hmm[sayac]));
else
std::cout << hmm[sayac];
}
}
}
You should also consider using an std::string instead of an array of char of arbitrary length. Also, take note that you have undefined behavior if the input string does not contain #.
I am trying to get a file path from the user in the getPath() function and return the path as a string. I am having trouble because the compiler says i need to use const char's and i dont know how to do that. How would I use const chars and what even are they. Also how do I print them to the console like in the main function.
#include <iostream>
#include <stdio.h>
#include <string.h>
char getPath() {
char path[64];
std::cout << "Input File Name For Debugging:";
gets(path);
std::cout << "Debugging: ";
puts(path);
return path[64];
}
int main(){
char path[64];
int pathlen = strlen(reinterpret_cast<const char *>(path));
//suppost to print the char array
for(int i; i < pathlen; i++){
std::cout << path[i];
}
return 0;
}
Lot's of misunderstandings
1) char is not a string, it's a character
2) An array of chars (e.g. char [64]) is not a string, its an array. It can hold a string but that's a subtly different idea
3) You don't use [64] when you mean the whole array, so return path[64]; is not the correct way to return a string.
4) Don't mix C++ I/O (std::cin, std::cout) with C I/O (puts, gets), it doesn't work reliably, Stick with C++ I/O so
std::cout << "Debugging: " << path << '\n';
not
std::cout << "Debugging: ";
puts(path);
5) You never call your getPath function so of course it doesn't execute
6) You don't initialise your loop variable i in your final loop so it has no predictable value. You should initialise i to 0
for(int i; i < pathlen; i++){
std::cout << path[i];
should be
for(int i = 0; i < pathlen; i++){
std::cout << path[i];
As you can see lots and lots of mistakes for a very short program. I'm going to show two different correct ways to write this program.
So there are two ways to represent a string in C++, there's the C++ way and there's the way that C++ inherits from C. The code you are writing above is trying to do things the C way, so I'll show that first, but actually the C++ way is much much easier. I'll show that second, but it's the way you should do things.
The first way is to use an array of characters to hold the string. But arrays have serious problems in C++. In particular it's not possible to return an array from a function, so your code above was never going to work, even if you'd fixed all the smaller problems. The way you get C++ to 'return' an array is a bit curious and I'm not going to explain it properly (you need to read a good C++ book). What you do is declare the array in the calling function and pass the array as a parameter. Here's your program written using this technique (and fixed of all the other problems).
#include <iostream>
void getPath(char path[], int n) {
std::cout << "Input File Name For Debugging:";
std::cin.getline(path, n);
std::cout << "Debugging: " << path << '\n';
}
int main(){
char path[64];
getPath(path, 64);
std::cout << path << '\n';
return 0;
}
Note I'm using getline to read the string, which is one C++ way to read a string. getline requires that you pass the size of the array it's going to read into, so I've passed that to getPath as well as the array itself.
Now for the easy way. C++ has it's own string type called std::string. You don't need to use tricky arrays at all. And the C++ string type can be returned from a function in the normal way. This makes for much more natural code. To use the C++ string type all you need to do is #include <string>. Here's your program rewritten to use the C++ string type
#include <iostream>
#include <string>
std::string getPath() {
std::cout << "Input File Name For Debugging:";
std::string path;
std::getline(std::cin, path);
std::cout << "Debugging: " << path << '\n';
return path;
}
int main(){
std::string path;
path = getPath();
std::cout << path << '\n';
return 0;
}
Notice this second program is closer to your original code, getPath has a return type, only it's std::string not char, and it has a return statement to return the path. This is the way you should be writing this code, the C++ string type will make writing string code much easier for you.
int main()
{
char hmm[1000];
cin.getline(hmm, 1000);
cout << hmm << endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!isdigit(hmm[sayac])) {
if (islower(hmm[sayac]))
cout << toupper(hmm[sayac]);
else if (isupper(hmm[sayac]))
cout << tolower(hmm[sayac]);
else
cout << hmm[sayac];
}
}
"Write a program that reads keyboard input to the # symbol and that echoes the input
except for digits, converting each uppercase character to lowercase, and vice versa.
(Don’t forget the cctype family.) "
I'm doing this exercise from the primer book. But when I run it, it returns the ascii order of the char, not the uppercase/lowercase version of the character. Couldn't figure out the problem. Can someone tell my why please?
(I may have other problems about the exercise, please don't correct them if I have. I want to fix it on my own (except the problem I explained), but I can't check the other ones as I have this problem.
When writing
std::cout << toupper('a');
the following happen:
int toupper(int ch) is called, and returns an integer whose value is 'A' (0x41).
std::basic_ostream::operator<<(std::cout, 0x41) is called, that is the int (2) overload since an int was provided.
Overall, it prints "65".
As a solution, you can cast back your upper case to a char:
std::cout << static_cast<char>(toupper('a'));
It's a question of representation. There is no difference between a character and that character's numeric value. It's all in how you choose to display it. For example, the character 'a' is just a constant with a value equal to the character's numeric value.
The problem you are having is that std::toupper and std::tolower return an int rather than a char. One reason for that is that they handle EOF values, which are not necessarily representable by char. As a consequence, std::cout see you are trying to print an int and not a char. The standard behavior for streaming an int is to print the number. The solution is then to cast your result to char to force the value to be interpreted as a character. You can use something like std::cout << static_cast<char>(std::toupper(hmm[sayac]));.
Try the following :
#include <cctype>
#include <iostream>
int main()
{
char hmm[1000];
std::cin.getline(hmm, 1000);
std::cout << hmm << std::endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!std::isdigit(hmm[sayac])) {
if (std::islower(hmm[sayac]))
std::cout << static_cast<char>(std::toupper(hmm[sayac]));
else if (isupper(hmm[sayac]))
std::cout << static_cast<char>(std::tolower(hmm[sayac]));
else
std::cout << hmm[sayac];
}
}
}
You should also consider using an std::string instead of an array of char of arbitrary length. Also, take note that you have undefined behavior if the input string does not contain #.
Let us say that we are reading a float with std::cin or from a file, and want to enforce the condition that it has two trailing decimal places:
E.g.
4.01 (valid)
4.001 (invalid - has three trailing decimal places)
a,47 (invalid, has two non [0-9] characters in 'a' and ',')
#556.53 (invalid, has '#')
(Just for context, in my example, I am parsing from a text file with several entries separated by spaces, validating each input, and storing them in a struct for further processing.)
How do we do it?
I found this from other sources in stackoverflow.
C++ How to check an input float variable for valid input
Here is the implementation. We read as string and only accept if any of the characters not digits (in perl, I suppose we could simply do a regex non-match [0-9]).
Apparently, the find_first_not_of method in string does this for us:
std::string a;
if(!(std::cin>>a)){
std::cout << "Invalid float entry " << std::endl;
}
if(a.find_first_not_of("1234567890.-")!=std::string::npos){
std::cout << "Invalid string to float" << std::endl;}
Next, we verify that the string has two decimal places by searching for the location of the decimal point.
if(a.size()-a.find(".")!=3){
std::cout << "Valid float but must have two decimal places \n";
}else{
std::cout << "Accept - valid float and has two decimal places \n";
}
Finally, we convert to float using stof.
float u = stof(a);
If you have a C++ compiler and standard library which implement C++11, then you can use a regular expression, which is very simple:
#include <iostream>
#include <regex>
#include <string>
int main(int argc, char** argv) {
std::string pattern("[-+]?\\d+\\.\\d\\d$");
std::regex reg(pattern);
for (int i = 1; i < argc; ++i) {
std::cout << argv[i]
<< (std::regex_match(argv[i], reg) ? " matched\n" : " didn't match\n");
}
return 0;
}
That test program takes the values as arguments rather than reading them from a file or stream, but modifying it to use the istream is trivial. There is no need to convert the string to a C-string; the first argument to regex_match can also be a std::string, or it can even be a pair of iterators whose value_type is char. In this case it just happened to be convenient to use a char*.
See it live on coliru.
At first this seemed easy to do but I was mistaken. I want to 'replace' a char (a variable) in a string with a int (value). But how?
I tried replace() because I'm working with a string and it worked but it will not work if I wish to change the value of the variable again to another
value because then the original variable will not be found. I have been struggling with this for the passed 2 days. Any help will be much appreciated on how to do this.
changeVar(string startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!";
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
Your help on this one will be much appreciated.
J
If you want to be able to replace the "variable" by the "value" as many times as you want, you should keep a copy of the original string and do the replacement from there only.
Another option is to undo the replacement (replace the value by the variable) and redo with another value, provided the undo can be done unambiguously.
I am sorry to hear this problem wasted your more than 2 days. You shouldcarefully read a basic C++ textbook. As your problem is a very basic one. If you understand the arguments passing for function, you will sort this out!
More specific, you function is not wrong, but just did not deliver the results you want. Because your function using argument, which will make a copy of argument startingExpr inside the function body, when you make replacement using "startingExpr[i] = val", the replacement is happened on the copy of startingExpr (which is a local variable just visible inside the function), your original startingExpr does change at all.
The solution is very simple, change argument passing with its reference, just add &, now the declaration your function should be: "changeVar(string startingExpr, char var, int val)"
Try the following code, which will demonstrate my explanation:
#include <iostream>
#include <string>
using namespace std;
//the original function which was reported had problem
// This because the function using parameter not reference
void changeVar(string startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!(But the replace is happend inside the function, the original string is not changed!)"<<endl;
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
// updating using the reference
//void changeVar(string & startingExpr, char var, int val)
void changeVar_refe(string & startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!(Now using reference, the replace is happend inside the original string, which will be changed!)"<<endl;
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
int main()
{
//lets test the original function
string my_name="Hi there, I am C++ taoism .";
cout<<"The original string is: "<<my_name<<endl;
//lets change a to A
changeVar(my_name,'a',65);
cout<<"The changed string is: "<<my_name<<endl;
cout<<endl;
cout<<"Using the reference to test ... "<<endl;
cout<<endl;
cout<<"The original string is: "<<my_name<<endl;
//lets change a to A
changeVar_refe(my_name,'a',65);
cout<<"The changed string is: "<<my_name<<endl;
//cout <<"Char A is int 65:"<<int('A')<<endl;
}
Your mistake is to assign the number that is different from the ASCII character represntation. In ASCII table characters '0', '1' .. '9' goes one after another. So you can rewrite your code as:
startingExpr[i] = '0' + val;
But please aware that this is good for one character case only. If you need to replace multiple chars then your solution without need for a function is that:
#include <iostream>
#include <string>
int
main()
{
std::string a("SomeVar1"), b("SomeVar356");
std::string::size_type index = std::string::npos;
std::cout << "Before: " << a << std::endl;
if ((index = a.rfind("1")) != std::string::npos)
a.replace(index, 1, std::to_string(2));
std::cout << "After: " << a << std::endl;
std::cout << "Before: " << b << std::endl;
if ((index = b.rfind("356")) != std::string::npos)
b.replace(index, 3, std::to_string(673));
std::cout << "After: " << b << std::endl;
return 0;
}
This is slightly optimized since it is using rfind (search from the end of the string).
P.S. As the comments suggested - you can use std::replace with reverse iterators and lambda for condition. Since it is available in C++11 I wrote a small example in universal style.