I have a need to split the following string into their corresponding alpahbets and numbers
CH1000003
ABC000123
WXYZ10001
Results I want are
st1: CH
st2: 1000003
st1: ABC
st2: 000123
st1: WXYZ
st2: 10001
Now I do have a working code but the amount of code I have written seems a bit too much. There has to be an easy way. Perhaps somehow use regex in C++? Suggestions?
My code:
std::string idToCheckStr="CH1000003";
//find length of string
int strLength = idToCheckStr.length();
cout << "idToCheckStr: " << idToCheckStr <<endl;
cout << "strLength : " << strLength <<endl;
string::iterator it;
int index = 0;
for ( it = idToCheckStr.begin() ; it < idToCheckStr.end(); it++ ,index++)
{
//check where the numbers start in the string
if (std::isdigit(*it) != 0)
{
cout<< "FOUND NUMBER!" <<endl;
cout<< index << ": " << *it <<endl;
break;
}
cout<< index << ": " << *it <<endl;
}
std::string firstPartStr = idToCheckStr.substr (0,index);
cout << "firstPartStr: " << firstPartStr <<endl;
std::string secondPartStr = idToCheckStr.substr (index,strLength);
cout << "secondPartStr: " << secondPartStr <<endl;
OUTPUT:
idToCheckStr: CH1000003
strLength : 9
0: C
1: H
FOUND NUMBER!
2: 1
firstPartStr: CH
secondPartStr: 1000003
Thanks to igor.
size_t first_digit = idToCheckStr.find_first_of("0123456789");
cout << "first_digit: " << first_digit <<endl;
std::string str1 = idToCheckStr.substr (0,first_digit);
cout << "str1: " << str1 <<endl;
std::string str2 = idToCheckStr.substr (first_digit,idToCheckStr.length());
cout << "str2: " << str2 <<endl;
OUTPUT:
first_digit: 2
str1: CH
str2: 1000003
Here is one of the simple ways to handle your problem.
I find this more understandable for you.
string s = "CH1000003";
// cin >> s; if you waant to read the input
string st1 = "", st2 = "";
for(auto ch : s) {
if(isdigit(ch)) st2 += ch;
else if(isalpha(ch)) st1 += ch;
else {} // if you want something else
}
cout << "st1: " << st1 << endl;
cout << "st2: " << st2 << endl;
You could indeed use regular expressions for this:
The pattern would be ([A-Z]+)([0-9]+), i.e. any combination of 1 or more uppercase letters followed by any combination of 1 or more numbers. The parentheses allow you to capture those 2 groups to be able to access them later on.
std::regex_match(line, matches, pattern) takes an input line, and tries to match it against a pattern. If it can, stores the matches in a std::smatch array; where the first entry is always the whole match, and the successive ones are for each capturing group. If it can't, it just returns false.
Should you need to relax the regular expression, e.g. allowing white spaces before, after, or in the middle of the input string, you could do it easily just changing the pattern: \s*([A-Z]+)\s*([0-9]+)\s*.
[Demo]
#include <fmt/core.h>
#include <iostream> // cout
#include <regex> // regex_match, smatch
#include <string>
int main() {
std::string line{};
std::regex pattern{R"(([A-Z]+)([0-9]+))"};
while (std::getline(std::cin, line)) {
std::smatch matches{};
if (std::regex_match(line, matches, pattern)) {
std::cout << fmt::format("line = '{}', alphabets = '{}', numbers = '{}'\n",
matches[0].str(), matches[1].str(), matches[2].str());
}
}
}
// Outputs:
//
// line = 'CH1000003', alphabets = 'CH', numbers = '1000003'
// line = 'ABC000123', alphabets = 'ABC', numbers = '000123'
// line = 'WXYZ10001', alphabets = 'WXYZ', numbers = '10001'
Related
This is for an intro c++ class, the prompt reads:
Print the number of words that begin with a certain character. Let the user enter that character.
Although, I'm not sure how to do this.
Do I use parsing strings? I tried this because they inspect string data type but I kept getting errors so I took it out and changed it to characters. I want to learn how to do the "total_num" (total number of words that start with the letter the user chooses) and I also need some help with my for loop.
Example of desired output
user types in: a
outputs: "Found 1270 words that begin with a"
user types in: E
outputs: "Found 16 words that begin with E"
user types in: #
outputs: "Found 0 words that begin with #"
(I think I got this part down for non-alphabetical)
The data is from a file called dict.txt, it's a list of many words.
Here's a small sample of what it contains:
D
d
D.A.
dab
dabble
dachshund
dad
daddy
daffodil
dagger
daily
daintily
dainty
dairy
dairy cattle
dairy farm
daisy
dally
Dalmatian
dam
damage
damages
damaging
dame
My program:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
const int NUM_WORD = 21880;//amount of words in file
struct dictionary { string word; };
void load_file(dictionary blank_array[])
{
ifstream data_store;
data_store.open("dict.txt");
if (!data_store)
{
cout << "could not open file" << endl;
exit(0);
}
}
int main()
{
dictionary file_array[NUM_WORD];
char user_input;
int total_num = 0;
load_file(file_array);
cout << "Enter a character" << endl;
cin >> user_input;
if (!isalpha(user_input))
{
cout << "Found 0 that begin with " << user_input << endl;
return 0;
}
for (int counter = 0; counter< NUM_WORD; counter++)
{
if (toupper(user_input) == toupper(file_array[counter].word[0]));
//toupper is used to make a case insensitive search
{
cout << "Found " << total_num << " that begin with " << user_input << endl;
//total_num needs to be the total number of words that start with that letter
}
}
}
There are a few things you can do to make your life simpler e.g. using a vector as the comment suggested.
Let's look at your for loop. There are some obvious syntax problems.
int main()
{
dictionary file_array[NUM_WORD];
char user_input;
int total_num = 0;
load_file(file_array);
cout << "Enter a character" << endl;
cin>>user_input;
if(!isalpha(user_input))
{
cout << "Found 0 that begin with " << user_input << endl;
return 0;
}
for(int counter = 0;counter< NUM_WORD; counter++)
{
if (toupper(user_input) == toupper(file_array[counter].word[0]));
// ^no semi-colon here!
//toupper is used to make a case insensitive search
{
cout<< "Found " << total_num << " that begin with "<<
user_input << endl;
//total_num needs to be the total number of words that start with that letter
}
}//<<< needed to end the for loop
}
Let's get the for loop right. You want to count the matches in a loop and then report when you have finished the loop.
int total_num = 0;
//get character and file
for(int counter = 0;counter< NUM_WORD; counter++)
{
if (toupper(user_input) == toupper(file_array[counter].word[0]))
^^^no semi-colon here!
{
++total_num;
}
}
cout<< "Found " << total_num << " that begin with "<< user_input << endl;
What I want is to have a multiple-line text input, and to be able to count the number of lower-case letters, upper-case letters, periods, commas, spaces, line-breaks, and other characters in the input.
I am trying to use just one string with getline for inputs in a while loop with a running count for each punctuation category.
I just don't know how to actually figure out how many of each character type there are in each line. Given a string, how do I count the number of each type?
Here is my code so far (obviously incomplete):
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cmath>
#include <string>
using namespace std;
int main(){
cout << "This program takes any number of sentences as inputs. " << endl;
cout << "It will count the number of lower-case letters and upper-case letters. " << endl;
cout << "It will also count the number of periods, exclamation marks, spaces, end-lines, etc. " << endl;
cout << " " << endl;
cout << "Please type your text, pressing enter whenever you wish to end a line. " << endl;
cout << "Use the EOF key (CTRL + Z on Windows) when you are finished. " << endl;
string InputString; // This is the string that will be used iteratively, for each line.
int NumberOfLowerCase = 0;
int NumberOfUpperCase = 0;
int NumberOfSpaces = 0; // spaces
int NumberOfTabs = 0; // tabs
int NumberOfPeriods = 0; // periods
int NumberOfCommas = 0; // commas
int NumberOfOtherChars = 0; // other characters
int NumberOfEnters = 0; // end of line, will be incremented each loop
do {
getline(cin, InputString); // input
cout << InputString << endl; // filler just to test the input
NumberOfLowerCase = NumberOfLowerCase + 0 // I don't know what I should be adding
// (obviously not zero, that's just a filler)
} while (!cin.eof() && cin.good());
system("pause");
return 0;
}
If you simply want the number of unique characters, use a set! You can push all of your characters into the set and then just check how big the set is and you'll be good to go!
If you actually want to know how many of each character there are you can use a map (which in fact uses a set under the hood!). With the map, given some character c, you could do
std::map<char, int> counter;
//do stuff...
counter[c]++; //increment the number of character c we've found
//do more stuff...
std::cout << "Found " << counter['A'] << " A's!" << std::endl;
See these helpful functions. Here what you would do:
std::string s = /*...*/;
for(auto c : s) {
if(std::islower(c)) ++NumberOfLowerCase;
else if(std::isupper(c)) ++NumberOfUpperCase;
else if(c == ' ') ++NumberOfSpaces;
else if(c == '\t') ++NumberOfTabs;
else if(c == '.') ++NumberOfPeriods;
else if(c == ',') ++NumberOfCommas;
else ++NumberOfOtherChars;
}
Here's a very simple example I wrote very quickly. Of course there are better ways of doing it, but this should give you an idea of how you could do that. One question: Are you reading from a file or from an istream directly from the console?
int lowerCase = 0;
int upperCase = 0;
int spaces = 0; // spaces
int tabs = 0; // tabs
int newLines = 0; // end of line, will be incremented each loop
int periods = 0; // periods
int commas = 0; // commas
int otherChars = 0;
// read from istream, char by char
for (char ch; cin >> noskipws >> ch;) {
// test which classification or char ch is and increment its count
if (islower(ch))
++lowerCase;
else if (isupper(ch))
++upperCase;
else if (ch == ' ')
++spaces;
else if (ch == '\t')
++tabs;
else if (ch == '\n')
++newLines;
else if (ch == '.')
++periods;
else if (ch == ',')
++commas;
else
++otherChars;
}
cout << "Number of characters of each type:\n";
cout << "lowerCase:\t" << lowerCase << '\n'
<< "upperCase:\t" << upperCase << '\n'
<< "spaces:\t\t" << spaces << '\n'
<< "tabs:\t\t" << tabs << '\n'
<< "periods:\t" << periods << '\n'
<< "commas:\t\t" << commas << '\n'
<< "newLines:\t" << newLines << '\n'
<< "otherChars:\t" << otherChars << '\n';
I've sat on this problem for quite some time and I can't figure out, what to do.
I am trying to write a programm, that reads a text file, searches and replaces string and saves the file under a new name. Depending on your input with minimum and maximum value as well as inkrement, several files are created.
Everything works except the replacing of a string (function replaceVariable).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <conio.h>
using namespace std;
string replaceVariable(string text1, string oldVariable, long double wert){
cout<< "replace-function open............."<<endl;
size_t foundAt = text1.find(oldVariable); //find position of old variable
cout<<"position old variable: "<<foundAt<<endl;
string newText = to_string(wert); //convert long double 'wert' to string
cout<<"new variable: "<<newText<<endl;
size_t lengthNewText = newText.length(); //find length of new string
string text2= text1.replace(foundAt, lengthNewText, newText); //replace with new string with length 'lengthNewText' starting at position 'foundAt'
return text2;
}
void writeFile ( string text, string filename ){
ofstream myfile;
myfile.open ( filename.c_str() );
myfile << text;
cout<<"file written.............."<<endl;
myfile.close();
}
template <typename T>
std::string to_string(T const& value) {
stringstream sstr;
sstr << value;
return sstr.str();
}
int main(){
ifstream inFile;
inFile.open("C:\\Users\\User\\Desktop\\Test\\testing.txt");//open the input file
if (inFile.is_open()){
cout<< "file open"<<endl<<endl;
stringstream strStream;
strStream << inFile.rdbuf();
string str = strStream.str();
cout << "---------------------------------------------------------------"<<endl;
cout<< str << endl;
cout << "---------------------------------------------------------------"<<endl<<endl;
string line;
string name;
long double minWert = 0;
long double maxWert = 0;
long double inkWert = 0;
cout << "Enter minimum value:" << endl;
cin >> minWert;
cout << "Enter maximum value:" << endl;
cin >> maxWert;
cout << "Enter inkrement:" << endl;
cin >> inkWert;
int numFiles = (maxWert-minWert)/inkWert + 1; //calculation number of files needed
cout << "minimum value: " << minWert << endl;
cout << "maximum value: " << maxWert << endl;
cout << "inkrement: " << inkWert << endl;
cout << "number of files: " << numFiles << endl<<endl<<endl;
string oldVariable = "xyz "; //string to be replaced, xyz followed by 5 spaces
for( int fileNum = 1; fileNum <= numFiles; ++fileNum ) {
cout<< "loop number: "<< fileNum<<endl;
string output = str;
replaceVariable(output, oldVariable, minWert);
cout << "---------------------------------------------------------------"<<endl;
cout << output << endl;
cout << "---------------------------------------------------------------"<<endl<<endl;
string text = output;
name = "C:\\Users\\User\\Desktop\\Test\\comp";
name += to_string( fileNum );
name += ".bdf";
writeFile( text, name );
cout<<minWert<<endl;
minWert = minWert+inkWert;
cout <<"new Minimalwert: "<< minWert<<endl<<endl;
}
inFile.close();
} else{cout << "Unable to open file";}
getch();
return 0;
}
I've already searched numerous sites and googled every thinkable combination.
Do you have any ideas what might help?
If your functionality of the function 'replaceVariable' is right then this might be the issue,
string output = str;
/*function replaceVariable is returning replaced string but you didn't receive
at the calling place and assign back to output(which you are writing in output file)*/
replaceVariable(output, oldVariable, minWert);
So replace like,
string output = replaceVariable(str, oldVariable, minWert);
Several points to be noted in your code.
First, string::find may return npos if the pattern string is not found, you should check that.
Second, string::replace does an inplace replacement on the original string, for better performance you could pass the text1 argument by reference.
Third, replaceVariable only replaces the first occurrence of the variable, is that really what you want?
Here is my version of replacing patterns in a string:
// replaces at most `limit` occurrences of pattern `p` in text `s` with string `repl`.
// if `limit` <= 0, replace all occurrences.
// returns number of replacement that actually took place.
int replace(std::string &s, const std::string &p, const std::string &repl, int limit=0) {
int nrepl = 0;
size_t pos = 0,
plen = p.length(),
rlen = repl.length(),
npos = std::string::npos;
while ((pos = s.find(p, pos)) != npos) {
s.replace(pos, plen, repl);
pos += rlen;
++nrepl;
if (limit > 0 && nrepl >= limit) break;
}
return nrepl;
}
Hope that helps.
Given input in the form of
fifteen,7,fourth-four,2,1,six
66,eight-six,99,eighteen
6,5,4,3,2,1
What can I use to read this into a format that I can then parse? The goal is to be able to sort the numbers and then print them back out, in order, in the same format that they were given to me. For example, the following should be printed as
1,2,six,7,fifteen,forty-four
eighteen,66,eighty-six,99
1,2,3,4,5,6
I have an idea of how the sorting should be done, I'm just having trouble figuring out the best way to read in the input. Currently, I'm using just doing this:
#include <iostream>
#include <string>
using namespace std;
int main() {
char word;
char arr[20];
int count = 0;
while (cin >> word) {
if (word == '\n') {
cout << "Newline detected.";
}
cout << "Character at: " << count << " is " << word << endl;
count++;
}
}
This does not work, because there is never a \n read in.
IMO the easiest way to do it would be to use std::istream's getline function with the ',' as the delimiter.
E.g. Something like.
char dummystr[256];
int count = 0;
while (cin.getline(dummystr, 256, ',')) {
cout << "Character at: " << count << " is " << dummystr << endl;
++count;
}
For newline delimiters with comma delimiters on each line (you really should just pick one):
char dummystr[256]; // not max size for the string
int count = 0;
while (cin.getline(dummystr, 256, '\n')) {
std::stringstream nested(dummystr);
char dummystr2[256];
while (nexted.getline(dummystr2, 256, ',')) {
cout << "Character at: " << count << " is " << dummystr << endl;
++count;
}
}
I have the following piece of code that takes in some words, stores them into a vector, sorts them, then counts how many times each word appears and outputs it:
typedef vector<double>::size_type vec_sz;
vector<string> words;
string c;
cout << "Enter some words!" << endl << endl;
while (cin >> c) {
words.push_back(c);
}
vec_sz size = words.size();
sort(words.begin(), words.end());
string current_word = words[0];
int count = 1;
for (int i = 1; i < size; i++) {
if (words[i] == current_word) {
count++;
}
else {
cout << "The word " + current_word + " appears " << count << " times." << endl;
current_word = words[i];
count = 1;
}
}
I enter some words:
word
word
lol
hello
lol
word
hello
^Z
I then get the following output:
The word hello appears 2 times.
The word lol appears 2 times.
But it never reaches the final set of words. I changed my loop to just print out each element in the vector and it does print out all of them. But for some reason this loop does not want to reach the final set of words. What is going wrong?
The last word is being reached, here:
else {
// Previous word printed
cout << "The word " + current_word + " appears " << count << " times." << endl;
// current_word set to last word
current_word = words[i];
count = 1;
}
And then the loop exits. So, you would need a final line outside the loop to print the last word and its count.
The count message is only printed when a different word is found. When the last word is found, a different word is not encountered so a message is not printed. You need a piece of code after the for to print out the count for last word.
There are other ways to achieve this, using a std::map<std::string, unsigned int> for example:
map<string, unsigned int> word_counts;
string c;
cout << "Enter some words!" << endl << endl;
while (cin >> c) {
word_counts[c]++;
}
for (map<string, unsigned int>::iterator wci = word_counts.begin();
wci != word_counts.end();
wci++)
{
cout << "The word " << wci->first << " appears " << wci->second << "times.";
}