How can I parse a string that looks like "xxxx-xxxx" and get those xxxx parts as a number? For an example, the user will type in "9349-2341" and I will get those numbers as two different integers.
I need to do that for a random number generator, which chooses the number between these xxxx variables.
Thanks.
You can use std::stringstream to extract numbers from string. It looks like that:
std::stringstream str_stream;
std::string str_to_parse = "1234-5678";
int num[2];
str_stream << str_to_parse;
str_stream >> num[0];
str_stream.ignore(1); // otherwise it will extract negative number (-5678)
str_stream >> num[1];
Also, there is C functions, like sscanf(). For example, your pattern can be extracted with this format: "%d-%d".
std::string str = "1234-5678";
std::string str1 = str.substr (0,4);
std::string str2 = str.substr(5, 4);
int n1 = std::stoi(str1);
int n2 = std::stoi(str2);
// do your random number generation between n1 and n2
Using regular expression
If your input is assured to resemble "xxxx-xxxx" where 'x' represents a digit, you can simply ultilize the following function:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main()
{
string input = "9349-2341";
// This pattern matches any string begining with 4 digits and ending with 4 digits, both parts seperated by a slash
string pattern = "([0-9]{4})-[0-9]{4}";
smatch matcher;
regex prog (pattern);
if (regex_search(input, matcher, prog))
{
auto x = matcher[1];
cout << x << " " << endl;
input = matcher.suffix().str();
}
else
{
cout << "Invalid input!" << endl;
}
return 0;
}
As for how to convert string to number, check out this article, from which the following segment is quoted:
string Text = "456";//string containing the number
int Result;//number which will contain the result
stringstream convert(Text); // stringstream used for the conversion initialized with the contents of Text
if ( !(convert >> Result) )//give the value to Result using the characters in the string
Result = 0;//if that fails set Result to 0
//Result now equal to 456
Or, simply as followed:
Using sscanf
#include <cstdio>
using namespace std;
int main(int argc, char ** argv)
{
char input[] = "1234-5678";
int result, suffix;
sscanf(input, "%i-%i", &result, &suffix);
printf("Output: '%i-%i'.\n", result, suffix);
return 0;
}
You should check out C++ reference websites, such as CPlusPlus.
Related
I want to read an input string and connect their values to variables in my class.
Some example Inputs might be:
78 C 15.48
3 B
87 P 15
0
..
The first argument is an int from 0-100, second a char and third int or float. A String can consist of one, two or three arguments which are separated by space. After reading a line, this program does some calculations and then expects another input until a 0 is entered or a break occurred.
To read an input String, i'm currently using
std::string str;
std::getline(std::cin, str);
My program already has the variables
int firstArgument;
char secondArgument;
float thirdFloatArgument;
int thirdIntArgument;
now, lets say str is: 46 C 87.3
after reading the line my variables should be:
firstArgument = 46;
secondArgument = 'C';
thirdFloatArgument = 87.3;
How can I extract the Information from the input String?
I was thinking about counting the spaces to see how much values are given and then separating the string via this delimiter,as the amount of arguments might vary. So:
int count = 0;
int length = str.length();
for(int i = 0; i < length; i++){
int c = str[i];
if(isspace(c)){
count++;
}
}
with space count being 2 I now know that 3 arguments were passed, but I don't know how to go on from there. Using std:istringstream might be an option but from what I've seen online it is mostly used in a while loop to print each word of a string in a new line or like that. But my input can vary in the amount of arguments so a loop would not work.
I think I need something like: "String before first ' ' is firstArgument, String between first and second ' ' is secondArgument, string after second ' ' is either thirdFloatArgument or thirdIntArgument (respectively if only one or two arguments are given, which can be determined with the amount of spaces). But how would I do this? Or are there some easier approaches?
Big thanks in advance!
As Some programmer dude mentioned it is a good idea to use std::istringstream to convert values from string to other data types. It allows you to treat input string the same way as you treat std::cin. Here is a code snippet that you can use in your case:
#include <string>
#include <iostream>
#include <algorithm>
#include <sstream>
struct Arguments {
int first{};
char second{};
double third{};
};
Arguments parseArgs(const std::string& inputLine) {
Arguments args;
const int argc = std::ranges::count(inputLine, ' ');
std::istringstream stream(inputLine);
if (argc >= 0) {
stream >> args.first;
}
if (argc >= 1) {
stream >> args.second;
}
if (argc >= 2) {
stream >> args.third;
}
return args;
}
int main() {
std::string inputLine{};
std::getline(std::cin, inputLine);
const auto args = parseArgs(inputLine);
std::cout << args.first << ", " << args.second << ", " << args.third << "\n";
}
Note that you have to compile this example using C++20 because I used std::ranges. If you do not have compiler that supports this standard you can use std::count(inputLine.cbegin(), inputLine.cend(), ' ');
I am writing c++ code to convert ebcdic to ascii
My main() is shown below
int main()
{
char text[100];
int position;
int count;
printf("Enter some text\n");
cin >> text;
char substring[] = "\\x";
if(strlen(text) 2 != 0)
{
cout << "Length of the string is not even" << endl;
}
else
{
position = 1;
int len_string;
len_string = strlen(text)/2;
cout<<"len_string"<<len_string<<endl;
for (count = 0; count < len_string;count++)
{
insert_substring(text, substring, position);
printf("text is s\n",text);
position = position + 4;
}
}
ebcdicToAscii((unsigned char*)text);
cout << "Converted text" <<text << endl;
char str[]="\xF5\x40\x40\x40\x40\xD4"; //Hardcoded string
ebcdicToAscii((unsigned char*)str);
printf ("converted str is s\n", str);
return 0;
}
Output:
Enter some text
F54040404040D4
len_string7
text is \xF54040404040D4
text is \xF5\x4040404040D4
text is \xF5\x40\x40404040D4
text is \xF5\x40\x40\x404040D4
text is \xF5\x40\x40\x40\x4040D4
text is \xF5\x40\x40\x40\x40\x40D4
text is \xF5\x40\x40\x40\x40\x40\xD4
Converted text**?*?*?*?*?*
converted str is 5 M
Before conversion I need to append \x infront of string
Example:
F540404040D4 must be inserting escape sequence \x
I have written the logic so I got the output:
\xF5\x40\x40/x40\x40\xD4
Now conversion of ebcdic to ascii starts using
ebcdicToAscii((unsigned char*)text);
But I am not getting desired output.
At the same time when I hardcode the string as
\xF5\x40\x40/x40\x40\xD4
the output is as expected
i.e
5 M
I am confused. Please Guide me. I have not shown called functions in code assuming that it is giving proper return.
You shouln't insert \x in inputted string and by the way with or without inserting, that will not work.
Here:
char str[]="\xF5\x40\x40\x40\x40\xD4";
it's just indication, that for example F5 is hexademical number and character with this ascii code should be used (not just symbols F and 5).
Look here for more info: What does \x mean in c/c++?
You should construct string from your input, that will store, not just symbols, but use each 2 bytes for ascii code.
For conversion you can for example use following code:
#include <iostream>
#include <string>
int main()
{
const std::string s ="F540404040D4";
std::string converted;
converted.reserve(s.size() / 2);
for (size_t i = 0; i < s.size(); i += 2)
{
const std::string tmp = s.substr(i, 2);
const int a = std::strtol(tmp.c_str(), 0, 16);
converted += static_cast<char>(a);
}
std::cout << converted.size() << std::endl;
}
i want to extract number string values of a char array. Actually I want to extract numbers embeded in file names for some file management. For example if there is a file name as file21 then i want the decimal number 21 from this file name.
How can i extract these values?
I tried the following but it results in an unexpected value. I think it is as a result of the implicit typecasting from the char to int while doing the arthimetic operation.
char * fname;
cout<<"enter file name";
cin>>fname;
int filenum=fname[4]%10+fname[5];
cout<<"file number is"<<filenum;
NOTE:
The filenamse are strictly in the format fileXX, XX being numbers between 01 and 99
You need to subtract '0' to get the decimal value of a digit character:
int filenum=(fname[4]-'0')*10+(fname[5]-'0');
Better yet, you should use atoi:
int filenum = atoi(fname+4);
You're getting undefined behavior because you're never allocating memory for the char* you read into:
char * fname = new char[16]; //should be enough for your filename format
or better yet
char fname[16];
Also, what do you expect:
fname[4]%10+fname[5];
to do? Magically concatenate the numbers?
First, you convert the first char to an int, multiply it by 10, convert the second char to an int and add to the first one. A simple google search for char to int would get you there.
How can i extract these values?
There are an infinite number of ways. One way is to use std::istringstream:
#include <string>
#include <sstream>
#include <iostream>
int main () {
std::string fname;
std::cout << "Enter file name: ";
std::getline(std::cin, fname);
int filenum;
std::istringstream stream(fname.substr(4,2));
if(stream >> filenum)
std::cout << "file number is " << filenum << "\n";
else
std::cout << "Merde\n";
}
Here is the simplest code:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
int filenum;
string fname;
cout<<"enter file name";
cin>>fname;
string str2 = fname.substr(4,2);
istringstream(str2) >> filenum;
cout<<"file number is"<<filenum;
return 0;
}
If your input is that much defined, the simplest solution is scanf:
int main()
{
int theNumber = 0;
scanf("file%d.txt", &theNumber);
printf("your number is %d", theNumber);
}
Check it out in action, reading from char* instead of stdio: http://codepad.org/JFqS70yI
scanf (and sscanf) also throws in checking for proper input format: returns number of fields read successfully. In this case if return value is any other than 1, the input was wrong.
I have a string which actually contains a number and a string, separated by ,, for instance "12,fooBar".
I would like to put it into separated variables, i.e. the number into unsigned int myNum and the string into std::string myStr.
I have the following snipped of code:
size_t pos1=value.find(',');
std::cout << value.substr(0, pos1) << " and "
<< (value.substr(0, pos1)).c_str() << std::endl;
This yields 12 and 1. Anything I missed here? What happend to the 2 in the second part?
Note: I isolated the problem to this snipped of code. I need c_str() to pass it to atoi to get the unsigend int. Here I don't want to print the second part.
Update: I actually get the string from levelDB Get. If I put a test string like I put here, it works.
The posted code produces the same substring: value.substr(0, pos1). Note that std::string::substr() does not modify the object, but returns a new std::string.
Example:
#include <iostream>
#include <string>
int main ()
{
std::string value ="12,fooBar";
unsigned int myNum;
std::string myStr;
const size_t pos1 = value.find(',');
if (std::string::npos != pos1)
{
myNum = atoi(value.substr(0, pos1).c_str());
myStr = value.substr(pos1 + 1);
}
std::cout << myNum << " and "
<< myStr << std::endl;
return 0;
}
Output:
12 and fooBar
EDIT:
If the unsigned int is the only piece required then the following will work:
unsigned int myNum = atoi(value.c_str());
as atoi() will stop at the first non-digit character (excluding optional leading - or +), in this case the ,.
The cleanest C++ style solution to this problem is to use a stringstream.
#include <sstream>
// ...
std::string value = "12,fooBar";
unsigned int myNum;
std::string myStr;
std::stringstream myStream(value);
myStream >> myNum;
myStream.ignore();
myStream >> myStr;
Your second substr should be value.substr(pos1+1,value.length())
One more option is using std::from_chars function from the 17th standard (< charconv > header):
int x;
from_chars(&s[i], &s.back(), x); // starting from character at index i parse
// the nearest interger till the second char pointer
There are different overloads for different types of value x (double etc.).
I'm trying to read just the integers from a text file structured like this....
ALS 46000
BZK 39850
CAR 38000
//....
using ifstream.
I've considered 2 options.
1) Regex using Boost
2) Creating a throwaway string ( i.e. I read in a word, don't do anything with it, then read in the score ). However, this is a last resort.
Are there any ways to express in C++ that I want the ifstream to only read in text that is an integer? I'm reluctant to use regular expressions if it turns out that there is a much simpler way to accomplish this.
why to make simple things complicated?
whats wrong in this :
ifstream ss("C:\\test.txt");
int score;
string name;
while( ss >> name >> score )
{
// do something with score
}
Edit:
it's in fact possible to work on streams directly with spirit than I suggested previously, with a parser:
+(omit[+(alpha|blank)] >> int_)
and one line of code(except for variable definitions):
void extract_file()
{
std::ifstream f("E:/dd/dd.trunk/sandbox/text.txt");
boost::spirit::istream_iterator it_begin(f), it_end;
// extract all numbers into a vector
std::vector<int> vi;
parse(it_begin, it_end, +(omit[+(alpha|blank)] >> int_), vi);
// print them to verify
std::copy(vi.begin(), vi.end(),
std::ostream_iterator<int>(std::cout, ", " ));
}
you get all numbers into a vector at once with one line, couldn't be simpler.
if you do not mind using boost.spirit2. the parser to get numbers from a line only is
omit[+(alpha|blank)] >> int_
to extract everything is
+(alpha|blank) >> int_
See the whole program below(Test with VC10 Beta 2):
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <algorithm>
#include <iterator>
using std::cout;
using namespace boost::spirit;
using namespace boost::spirit::qi;
void extract_everything(std::string& line)
{
std::string::iterator it_begin = line.begin();
std::string::iterator it_end = line.end();
std::string s;
int i;
parse(it_begin, it_end, +(alpha|blank)>>int_, s, i);
cout << "string " << s
<< "followed by nubmer " << i
<< std::endl;
}
void extract_number(std::string& line)
{
std::string::iterator it_begin = line.begin();
std::string::iterator it_end = line.end();
int i;
parse(it_begin, it_end, omit[+(alpha|blank)] >> int_, i);
cout << "number only: " << i << std::endl;
}
void extract_line()
{
std::ifstream f("E:/dd/dd.trunk/sandbox/text.txt");
std::string s;
int i;
// iterated file line by line
while(getline(f, s))
{
cout << "parsing " << s << " yields:\n";
extract_number(s); //
extract_everything(s);
}
}
void extract_file()
{
std::ifstream f("E:/dd/dd.trunk/sandbox/text.txt");
boost::spirit::istream_iterator it_begin(f), it_end;
// extract all numbers into a vector
std::vector<int> vi;
parse(it_begin, it_end, +(omit[+(alpha|blank)] >> int_), vi);
// print them to verify
std::copy(vi.begin(), vi.end(),
std::ostream_iterator<int>(std::cout, ", " ));
}
int main(int argc, char * argv[])
{
extract_line();
extract_file();
return 0;
}
outputs:
parsing ALS 46000 yields:
number only: 46000
string ALS followed by nubmer 46000
parsing BZK 39850 yields:
number only: 39850
string BZK followed by nubmer 39850
parsing CAR 38000 yields:
number only: 38000
string CAR followed by nubmer 38000
46000, 39850, 38000,
You can call ignore to have in skip over a specified number of characters.
istr.ignore(4);
You can also tell it to stop at a delimiter. You would still need to know the maximum number of characters the leading string could be, but this would also work for shorter leading strings:
istr.ignore(10, ' ');
You could also write a loop that just reads characters until you see the first digit character:
char c;
while (istr.getchar(c) && !isdigit(c))
{
// do nothing
}
if (istr && isdigit(c))
istr.putback(c);
here goes :P
private static void readFile(String fileName) {
try {
HashMap<String, Integer> map = new HashMap<String, Integer>();
File file = new File(fileName);
Scanner scanner = new Scanner(file).useDelimiter(";");
while (scanner.hasNext()) {
String token = scanner.next();
String[] split = token.split(":");
if (split.length == 2) {
Integer count = map.get(split[0]);
map.put(split[0], count == null ? 1 : count + 1);
System.out.println(split[0] + ":" + split[1]);
} else {
split = token.split("=");
if (split.length == 2) {
Integer count = map.get(split[0]);
map.put(split[0], count == null ? 1 : count + 1);
System.out.println(split[0] + ":" + split[1]);
}
}
}
scanner.close();
System.out.println("Counts:" + map);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
readFile("test.txt");
}
}
fscanf(file, "%*s %d", &num);
or %05d if you have leading zeros and fixed width of 5....
sometimes the fastest way to do things in C++ is to use C. :)
You can create a ctype facet that classifies letters as white space. Create a locale that uses this facet, then imbue the stream with that locale. Having that, you can extract numbers from the stream, but all letters will be treated as white space (i.e. when you extract numbers, the letters will be ignored just like a space or a tab would be):
Such a locale can look like this:
#include <iostream>
#include <locale>
#include <vector>
#include <algorithm>
struct digits_only: std::ctype<char>
{
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
if (rc['0'] == std::ctype_base::space)
std::fill_n(&rc['0'], 9, std::ctype_base::mask());
return &rc[0];
}
};
Sample code to use it could look like this:
int main() {
std::cin.imbue(std::locale(std::locale(), new digits_only()));
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::ostream_iterator<int>(std::cout, "\n"));
}
Using your sample data, the output I get from this looks like this:
46000
39850
38000
Note that as it stands, I've written this to accept only digits. If (for example) you were reading floating point numbers, you'd also want to retain '.' (or the locale-specific equivalent) as the decimal point. One way to handle things is to start with a copy of the normal ctype table, and then just set the things you want to ignore as space.