I would like to count the numbers in a string /c++ - c++

I have tried to count the numbers in a string but it doesnt work and I think it is logically good. I am a beginner in programming.
I know it works for one-digit numbers but that's intentional.
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int main()
{
int numbs [10] = {0,1,2,3,4,5,6,7,8,9};
string str1;
cin >> str1;
vector <unsigned int> positions;
for (int a = 0 ;a <=10;a++)
{
int f = numbs[a];
string b = to_string(f);
unsigned pos = str1.find(b,0);
while(pos !=string::npos)
{
positions.push_back(pos);
pos = str1.find(b,pos+1);
break;
}
}
cout << "The count of numbers:" << positions.size() <<endl;
return 0;
}

If you need only to count digits in a string then there is no sense to use std::vector. You can count them without the vector. For example
#include <iostream>
#include <string>
int main()
{
std::string s( "A12B345C789" );
size_t count = 0;
for ( std::string::size_type pos = 0;
( pos = s.find_first_of( "0123456789", pos ) ) != std::string::npos;
++pos )
{
++count;
}
std::cout << "The count of numbers: " << count << std::endl;
return 0;
}
The output is
The count of numbers: 8
Also you could use standard algorithm std::count_if defined in header <algorithm>
For example
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main()
{
std::string s( "A12B345C789" );
size_t count = std::count_if( s.begin(), s.end(),
[]( char c ) { return std::isdigit( c ); } );
std::cout << "The count of numbers: " << count << std::endl;
return 0;
}
The output is
The count of numbers: 8
If you need to count numbers instead of digits in a string then you should use standard C function strtol or C++ function std::stoi

Use substrings to extract every part of string with a delimiter(normally a space). Then convert each substring to number. The ones that qualify and converts probably are the numbers in your string. See how many you get.

You might also be interested in the C++ function "isdigit":
http://www.cplusplus.com/reference/locale/isdigit/
For example:
include <iostream>
#include <string.h>
#include <vector>
#include <locale> // std::locale, std::isdigit
using namespace std;
int main()
{
// Initialze array with count for each digit, 0 .. 9
int counts[10] = {0, 0, 0, 0, 0, 0, 0,0, 0, 0 };
int total = 0;
// Read input string
string str;
cin >> str;
// Parse each character in the string.
std::locale loc;
for (int i=0; i < str.length(); i++) {
if isdigit (str[i], loc) {
int idx = (int)str[i];
counts[idx]++
total++;
}
// Print results
cout << "The #/digits found in << str << " is:" << total << endl;
// If you wanted, you could also print the total for each digit ...
return 0;
}

Related

Function find() works incorrect

My task is to check if a number contains 8 or not. I've converted the number into a std::string and have used its find() method. But it only works with a number which starts with 8, for example 8, 81, 881, etc. For numbers like 18, 28, etc, it doesn't work.
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
unsigned long long g = 0;
int main()
{
string str;
cin >> str;
int f = stoi(str);
string eig = "8";
for (int a = 1; a <= f; a++)
{
string b = to_string(a);
if (b.find(eig) != size_t() && b.rfind(eig) != size_t())
{
cout << "It worked with " << b << "\n";
g++;
}
}
cout << g;
}
You are using std::string::find() and std::string::rfind() incorrectly. They do not return size_t() if a match is not found. They return std::string::npos (ie size_type(-1)) instead. size_t() has a value of 0, so find(...) != size_t() will evaluate as true if no match is found at all (-1 != 0), or any character other than the first character is matched (>0 != 0). This is not what you want.
Also, your use of rfind() is redundant, since if find() finds a match then rfind() is guaranteed to also find a match (though just not necessarily the same match, but you are not attempting to differentiate that).
Try this:
#include <iostream>
#include <string>
using namespace std;
unsigned long long g = 0;
int main()
{
int f;
cin >> f;
for (int a = 1; a <= f; a++)
{
string b = to_string(a);
if (b.find('8') != string::npos)
{
cout << "It worked with " << b << "\n";
++g;
}
}
cout << g;
}
#include <iostream>
#include <string>
#include <cassert>
int main(int argc, char **argv) {
auto s = std::to_string(1234567890);
assert(s.find('8') != std::string::npos);
return 0;
}
Is this what you want?

How do I remove repeated words from a string and only show it once with their wordcount

Basically, I have to show each word with their count but repeated words show up again in my program.
How do I remove them by using loops or should I use 2d arrays to store both the word and count?
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <conio.h>
#include <time.h>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
_getch();
}
char* getstring()
{
static char pa[100];
cout << "Enter a paragraph: " << endl;
cin.getline(pa, 1000, '#');
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token != NULL) {
int wordcount = 0;
if (token != NULL) {
int sizex = strlen(token);
//char** fin;
int j;
for (int i = 0; i <= size; i++) {
for (j = 0; j < sizex; j++) {
if (pa[i + j] != token[j]) {
break;
}
}
if (j == sizex) {
wordcount++;
}
}
//for (int w = 0; w < size; w++)
//fin[w] = token;
//cout << fin[w];
cout << token;
cout << " " << wordcount << "\n";
}
token = strtok_s(NULL, sepa, &nexttoken);
}
}
This is the output I get:
I want to show, for example, the word "i" once with its count of 5, and then not show it again.
First of all, since you are using c++, I would recommend you to split text in c++ way(some examples are here), and store every word in map or unordered_map. Example of my realization you can find here
But if you don't want to rewrite your code, you can simply add a variable that will indicate whether a copy of the word was found before or after the word position. If a copy was not found in front, then print your word
This post gives an example to save each word from your 'strtok' function into a vector of string. Then, use string.compare to have each word compared with word[0]. Those indexes match with word[0] are marked in an int array 'used'. The count of match equals to the number marks in the array used ('nused'). Those words of marked are then removed from the vector, and the remaining carries on to the next comparing process. The program ends when no word remained.
You may write a word comparing function to replace 'str.compare(str2)', if you prefer not to use std::vector and std::string.
#include <iostream>
#include <string>
#include <vector>
#include<iomanip>
#include<cstring>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
}
char* getstring()
{
static char pa[100] = "this is a test and is a test and is test.";
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
std::vector<std::string> word;
int used[64];
std::string tok;
int nword = 0, nsize, nused;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token)
{
word.push_back(token);
++nword;
token = strtok_s(NULL, sepa, &nexttoken);
}
for (int i = 0; i<nword; i++) std::cout << word[i] << std::endl;
std::cout << "total " << nword << " words.\n" << std::endl;
nsize = nword;
while (nsize > 0)
{
nused = 0;
tok = word[0] ;
used[nused++] = 0;
for (int i=1; i<nsize; i++)
{
if ( tok.compare(word[i]) == 0 )
{
used[nused++] = i; }
}
std::cout << tok << " : " << nused << std::endl;
for (int i=nused-1; i>=0; --i)
{
for (int j=used[i]; j<(nsize+i-nused); j++) word[j] = word[j+1];
}
nsize -= nused;
}
}
Notice that the removal of used words has to do in backward order. If you do it in sequential order, the marked indexes in the 'used' array will need to be changed. A running test:
$ ./a.out
this is a test and is a test and is test.
this
is
a
test
and
is
a
test
and
is
test
total 11 words.
this : 1
is : 3
a : 2
test : 3
and : 2
I read your last comment.
But I am very sorry, I do not know C. So, I will answer in C++.
But anyway, I will answer with the C++ standard approach. That is usually only 10 lines of code . . .
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <regex>
// Regex Helpers
// Regex to find a word
static const std::regex reWord{ R"(\w+)" };
// Result of search for one word in the string
static std::smatch smWord;
int main() {
std::cout << "\nPlease enter text: \n";
if (std::string line; std::getline(std::cin, line)) {
// Words and its appearance count
std::map<std::string, int> words{};
// Count the words
for (std::string s{ line }; std::regex_search(s, smWord, reWord); s = smWord.suffix())
words[smWord[0]]++;
// Show result
for (const auto& [word, count] : words) std::cout << word << "\t\t--> " << count << '\n';
}
return 0;
}

Generate random letter array and count occurences

Hello I am trying to generate a random array of the length that the user inputs. My array should then print and display the occurences of those letters in the array. So far this only prints up to the letter g and the occurences are incorrect. If someone could tell me what I am doing wrong it would help alot. Thank you.
#include <iostream>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
int main()
{
srand(time(0));
int i, num;
char ch;
char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int freq[26]={0};
cout << "How many letters do you want in your string? ";
cin >> num;
for (i=0; i < num; i++)
{
ch = chars[rand()%26];
chars[i]=ch;
freq[i] +=1;
cout << ch;
}
for (char lower = 'a'; lower <='z'; lower++)
{
cout << "\nLetter" << lower << "is " << freq[lower] << "times";
}
}
Problem 1
The lines
chars[i]=ch;
freq[i] +=1;
are not right. You need to use:
int index = ch - 'a';
freq[index] += 1;
Problem 2
The index in the for loop for printing the data is not correct either.
You need to use:
for (char lower = 'a'; lower <='z'; lower++)
{
int index = lower - 'a';
cout << "\nLetter" << lower << "is " << freq[index] << "times";
}
Important Note
It is worth noting that the C++ standard does not guarantee that lower case letters are contiguous. (Thanks #MartinBonner). For instance, if your system uses EBCDIC encoding your program won't work.
To make your code robust, it will be better to use a std::map.
int main()
{
srand(time(0));
int i, num;
char ch;
char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
std::map<char, int> freq;
// Initialize freq.
for ( ch : chars )
{
freq[ch] = 0;
}
cout << "How many letters do you want in your string? ";
cin >> num;
for (i=0; i < num; i++)
{
ch = chars[rand()%26];
freq[ch] +=1;
}
for (auto item : freq )
{
cout << "\nLetter" << item.first << "is " << item.second << "times";
}
}
You might wanna give a look to C++11 Pseudo-random number generation here is a short way of generating the range that you want using this:
#include <algorithm>
#include <array>
#include <random>
#include <vector>
using namespace std;
int main()
{
int arraySize = 35;
mt19937 engine{random_device{}()};
uniform_int_distribution<> dist{'a', 'z'};
vector<char> vec;
generate_n(back_inserter(vec), arraySize, [&]() { return static_cast<char>(dist(engine); }));
//To count occurrences
array<int, 26> freq;
for (auto c : vec) { ++freq[c-'a']; }
return 0;
}
You should not write into chars, and freq should be extended to cover the a...z range (the ASCII codes), which it does not. Also, increase at index ch, not at i.
I do not even know that range from the top of my head, but it could be modified to track all possible bytes instead (0...255), see result on https://ideone.com/xPGls7
List of changes:
int freq[256]={0}; // instead of int freq[26]={0};
// chars[i]=ch; is removed
freq[ch] +=1; // instead of freq[i] +=1;
Then it works.
Using lambda functions to do most of the work.
#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <ostream>
#include <random>
#include <string>
#include <utility>
#include <vector>
using namespace std::string_literals;
int main()
{
std::mt19937::result_type seed = std::random_device{}();
auto engine = std::mt19937(seed);
auto dist = std::uniform_int_distribution<>('a', 'z');
auto random_letter = [&engine, &dist]() { return static_cast<char>(dist(engine)); };
std::cout << "How many letters do you want to generate? "s;
int n;
if (!(std::cin >> n)) { return EXIT_FAILURE; }
auto letters = std::vector<char>();
std::generate_n(std::back_inserter(letters), n, random_letter);
auto zero = std::map<char, int>();
auto const frequencies = std::accumulate(std::cbegin(letters), std::cend(letters), zero,
[](auto& acc, auto c)
{
++acc[c];
return acc;
});
for (auto const [c, freq] : frequencies)
{
std::cout << "The letter '"s << c << "' appeared "s << freq << " times." << std::endl;
}
return 0;
}

How to read a integer value from a string in C++? [duplicate]

I realize that this question may have been asked several times in the past, but I am going to continue regardless.
I have a program that is going to get a string of numbers from keyboard input. The numbers will always be in the form "66 33 9" Essentially, every number is separated with a space, and the user input will always contain a different amount of numbers.
I'm aware that using 'sscanf' would work if the amount of numbers in every user-entered string was constant, but this is not the case for me. Also, because I'm new to C++, I'd prefer dealing with 'string' variables rather than arrays of chars.
I assume you want to read an entire line, and parse that as input. So, first grab the line:
std::string input;
std::getline(std::cin, input);
Now put that in a stringstream:
std::stringstream stream(input);
and parse
while(1) {
int n;
stream >> n;
if(!stream)
break;
std::cout << "Found integer: " << n << "\n";
}
Remember to include
#include <string>
#include <sstream>
The C++ String Toolkit Library (Strtk) has the following solution to your problem:
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>
#include <iterator>
#include "strtk.hpp"
int main()
{
std::string s = "1 23 456 7890";
std::deque<int> int_list;
strtk::parse(s," ",int_list);
std::copy(int_list.begin(),
int_list.end(),
std::ostream_iterator<int>(std::cout,"\t"));
return 0;
}
More examples can be found Here
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
#include <iostream>
int main() {
std::string input;
while ( std::getline( std::cin, input ) )
{
std::vector<int> inputs;
std::istringstream in( input );
std::copy( std::istream_iterator<int>( in ), std::istream_iterator<int>(),
std::back_inserter( inputs ) );
// Log process:
std::cout << "Read " << inputs.size() << " integers from string '"
<< input << "'" << std::endl;
std::cout << "\tvalues: ";
std::copy( inputs.begin(), inputs.end(),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
}
}
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
using namespace std;
int ReadNumbers( const string & s, vector <int> & v ) {
istringstream is( s );
int n;
while( is >> n ) {
v.push_back( n );
}
return v.size();
}
int main() {
string s;
vector <int> v;
getline( cin, s );
ReadNumbers( s, v );
for ( int i = 0; i < v.size(); i++ ) {
cout << "number is " << v[i] << endl;
}
}
// get string
std::string input_str;
std::getline( std::cin, input_str );
// convert to a stream
std::stringstream in( input_str );
// convert to vector of ints
std::vector<int> ints;
copy( std::istream_iterator<int, char>(in), std::istream_iterator<int, char>(), back_inserter( ints ) );
Here is how to split your string into strings along the spaces. Then you can process them one-by-one.
Generic solution for unsigned values (dealing with prefix '-' takes an extra bool):
template<typename InIter, typename OutIter>
void ConvertNumbers(InIter begin, InIter end, OutIter out)
{
typename OutIter::value_type accum = 0;
for(; begin != end; ++begin)
{
typename InIter::value_type c = *begin;
if (c==' ') {
*out++ = accum; accum = 0; break;
} else if (c>='0' && c <='9') {
accum *= 10; accum += c-'0';
}
}
*out++ = accum;
// Dealing with the last number is slightly complicated because it
// could be considered wrong for "1 2 " (produces 1 2 0) but that's similar
// to "1 2" which produces 1 0 2. For either case, determine if that worries
// you. If so: Add an extra bool for state, which is set by the first digit,
// reset by space, and tested before doing *out++=accum.
}
Try strtoken to separate the string first, then you will deal with each string.

How to find a particular value from a string in C++

I have this string "67030416680001337D4912601000000000000"
I want to take value before letter "D".
also want value 4 digits only after "D".
I have tried using:
string sPanNo = sTrkData.substr(0,17);
string sExpDate = sTrkData.substr(18, 4);
but problem is string before letter "D" will vary in length.
You can use string::find_first_of(), something like:
string::size_type dPos = sTrkData.find_first_of('D');
if (dPos != string::npos) {
string sPanNo = sTrkData.substr(0, dPos);
string sExpDate = sTrkData.substr(dPos + 1, 4);
}
You have to use member function find
For example
std::string::size_type n = sTrkData.find( 'D' );
string sPanNo = sTrkData.substr( 0, n );
string sExpDate;
if ( n != std::string::npos ) sExpDate = sTrkData.substr( n + 1, 4 );
You can use a regular expression to validate your input and extract the desired data in one step:
#include <iostream>
#include <regex>
#include <string>
int main() {
using namespace std;
string input("67030416680001337D4912601000000000000");
regex re("(\\d+)D(\\d{4})\\d+");
match_results<string::const_iterator> m;
if (regex_match(input, m, re)) {
cout << m[1].str() << endl;
cout << m[2].str() << endl;
} else {
cout << "invalid input\n";
}
}
or use <regex> C++ 11
#include <iostream>
#include <regex>
#include <string>
using namespace std;
std::regex base_regex ( "(\\d+)D(\\d{4})\\d+" );
std::smatch base_match;
string numberstring = "67030416680001337D4912601000000000000";
if (std::regex_match(numberstring, base_match, base_regex))
{
std::ssub_match base_sub_match = base_match[1];
std::string number1 = base_sub_match.str();
base_sub_match = base_match[2];
std::string number2 = base_sub_match.str();
cout << number1 << endl;
cout << number2 << endl;
}