How do I extract all the numbers in a string where the numbers are interspersed with letters? - c++

How do I loop through a string consisting of numbers and letters and add only numbers to the vector?
For example if the input is:
e385p336J434Y26C2Z6X5Z2
I want to get a vector of int like this:
number = {385, 336, 434, 26, 2, 6, 5, 2}
The best I got was to iterate over the line and add all the digits like that:
#include <bits/stdc++.h>
int main(){
string f = "e385p336J434Y26C2Z6X5Z2";
vector<int> f_numb;
string sum;
for (int i = 0; i < f.size(); ++i){
if (('0' <= f[i]) && (f[i] <= '9')){
sum += (f[i]);
}
}
//std::cout << sum << std::endl;
vector<int> m_numb;
for (int i = 0; i < sum.size(); ++i){
m_numb.push_back(sum[i] - '0');
}
int sm;
for (int i = 0; i < m_numb.size(); ++i){
sm += m_numb[i];
std::cout << m_numb[i] << " ";
}
std::cout << std::endl;
}

Foregoing the unstated reason you're not using std::isdigit, you can/should simply build each number as you process its digits. Note that the code below does NOT check, nor care, about unsigned overflow, and makes no attempt at processing negative numbers.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string f = "e385p336J434Y26C2Z6X5Z2";
std::vector<unsigned int> f_numb;
for (auto it = f.begin(); it != f.end();)
{
if ('0' <= *it && *it <= '9')
{
unsigned int sm = 0;
for (;it != f.end() && '0' <= *it && *it <= '9'; ++it)
sm = (sm * 10) + (*it - '0');
f_numb.emplace_back(sm);
}
else
{
++it;
}
}
for (auto x : f_numb)
std::cout << x << ' ';
std::cout << '\n';
}
Output
385 336 434 26 2 6 5 2
That, assuming I understand your question vs. your code, which differ highly in their apparent goals.

Another aproach making more use of standard library functions.
Live demo here : https://onlinegdb.com/8eEgREuEN
I tend to make functions of substeps so I can test them individually
#include <algorithm>
#include <iterator> // back_inserter
#include <string>
#include <vector>
#include <iostream>
#include <string_view>
// I like to make functions for substeps (they tend to be reusable)
std::vector<std::string> get_number_substrings(const std::string& input)
{
static const std::string_view digits{ "0123456789" };
std::vector<std::string> substrings;
auto start_pos = input.find_first_of(digits, 0ul);
auto end_pos = start_pos;
auto max_length = input.length();
while (start_pos < max_length)
{
end_pos = std::min(max_length, input.find_first_not_of(digits, start_pos));
if (end_pos != start_pos)
{
substrings.emplace_back(&input[start_pos], end_pos - start_pos);
start_pos = input.find_first_of(digits, end_pos);
}
}
return substrings;
}
std::vector<int> get_numbers(const std::string& input)
{
auto numbers = get_number_substrings(input);
std::vector<int> output;
// now transform the string to vector<int>
// the back_inserter is needed because output doesn't have allocated memory yet
// and that needs to be build up during the transform.
// https://en.cppreference.com/w/cpp/iterator/back_inserter
// https://en.cppreference.com/w/cpp/algorithm/transform
std::transform(numbers.begin(), numbers.end(), std::back_inserter(output), [](const std::string& string)
{
return std::stoi(string);
});
return output;
}
int main()
{
std::string input{ "e385p336J434Y26C2Z6X5Z2" };
auto output = get_numbers(input); // output will be a std::vector<int>
// Use range based for loop
// https://en.cppreference.com/w/cpp/language/range-for
bool comma = false;
for (const int value : output)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
return 0;
}

Will this work for you?
std::string f = "e385p336J434Y26C2Z6X5Z2";
std::vector<int> f_numb;
std::string sum;
#define MAX_DIGITS 25
char aBuildNumber[MAX_DIGITS];
int aBuildCount=0;
std::vector<int> m_numb;
for (int i = 0; i < f.size(); ++i)
{
if (!isdigit(f[i]) || aBuildCount>=MAX_DIGITS-1)
{
if (aBuildCount>0) m_numb.push_back(atoi(aBuildNumber));
aBuildCount=0;
}
else {aBuildNumber[aBuildCount++]=f[i];aBuildNumber[aBuildCount]=0;}
}
if (aBuildCount>0) m_numb.push_back(atoi(aBuildNumber));
int sm=0;
for (int i = 0; i < m_numb.size(); ++i)
{
sm += m_numb[i];
std::cout << m_numb[i] << " ";
}
std::cout << std::endl;

Related

Why is it that my code is only showing the last element in the array even though It should be showing the element with the most amount of characters

#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
vector<string> createvector() {
vector<string> words;
string names;
cout << "Please enter 5 different words: " << endl;
for (int i = 0; i < 5; i++) {
cin >> names;
words.push_back(names);
}
return (words);
}
void mostchar(vector<string> words) {
string w1 = words[0];
string largestword;
for (int i = 1; i < 5; i++) {
if (words[i] > w1) {
largestword = words[i];
}
}
cout << "The largest word is: " << largestword;
}
int main()
{
vector<string> words;
string names;
words = createvector();
mostchar(words);
}
I do not understand why it's picking the last element or the second to last element every time. Right I've tried to change for(int i = 1; i < 5; i++) but it makes no difference to what I do.
For starters you are comparing strings in the lexicographical order.
if (words[i] > w1) {
Secondly you always comparing with the word in the first element of the array
if (words[i] > w1) {
and the variable w1 is not being changed within the loop. So any last element in the vector that is greater than w1 will be assigned to the variable largestword.
Using the for loop the function can look the following way
void mostchar( const std::vector<std::string> &words )
{
size_t largestword = 0;
for ( size_t i = 1; i < words.size(); i++ )
{
if ( words[largestword].size() < words[i].size() )
{
largestword = i;
}
}
if ( largestword != words.size() )
{
std::cout << "The largest word is: " << words[largestword] << '\n';
}
}
Pay attention to that in general case the user can pass to the function an empty vector. You must check such a possibility within the function.
Bear in mind that there is standard algorithm std::max_element that can be used instead of manually written for loop.
For example
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
void mostchar( const std::vector<std::string> &words )
{
auto largestword = std::max_element( std::begin( words ), std::end( words ),
[]( const auto &a, const auto &b )
{
return a.size() < b.size();
} );
if ( largestword != std::end( words ) )
{
std::cout << "The largest word is: " << *largestword << '\n';
}
}
There are a couple issues here:
1: You should use something like .length() to compare "length"
2: You are comparing the next word in the array to words[0] every time.
EDIT: To further explain this, there is an assignment of string w1 = words[0];. w1 is then used in the if in the for loop here:
string w1 = words[0];
string largestword;
for (int i = 1; i < 5; i++) {
if (words[i] > w1) {
largestword = words[i];
}
}
resulting in the value of words[0] being the value repeatedly compared in the loop.
Adjust the comparison line to if (words[i].length() > largestword.length()) and that solves both problems. You can elminate w1 entirely this way as well.
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
vector<string> createvector() {
vector<string> words;
string names;
cout << "Please enter 5 different words: " << endl;
for (int i = 0; i < 5; i++) {
cin >> names;
words.push_back(names);
}
return (words);
}
void mostchar(vector<string> words) {
string largestword;
for (int i = 0; i < 5; i++) {
if (words[i].length() > largestword.length()) {
largestword = words[i];
}
}
cout << "The largest word is: " << largestword;
}
int main()
{
vector<string> words;
string names;
words = createvector();
mostchar(words);
}

Parsing does not work: terminate called after throwing an instance of "std::invalid argument"

I want to have a function which returns a vector of 2 integers. The input is a string.
The layout of the string that is inserted should always be like this: "COORDINATES 123 456" with the coordinates being integers of any length.
If the string is "COORDINATES 123" or "COORDINATES 123 456 789", the function should return an empty vector.
#include <iostream>
#include <string>
#include <vector>
std::vector<int> getCoordinates(std::string string){
auto count = 0;
std::string coordinates;
int coordinatesInt;
std::vector<int> vector;
int i, j = 0;
for(int i = 0; i < string.size(); i++){
if(string.at(i) == ' '){
count++;
j = 1;
while(string.at(i+j) != ' ' && string.at(i+j) <= string.length()){
coordinates.push_back(string.at(i+j));
j++;
}
coordinatesInt = std::stoi(coordinates);
vector.push_back(coordinatesInt);
}
}
if(count != 2){
vector.clear();
}
std::cout << count << std::endl;
return vector;
}
int main()
{
std::string coordinates = "COORDINATES 123 456";
std::vector<int> vectorWithCoordinates = getCoordinates(coordinates);
std::cout << vectorWithCoordinates[1] << std::endl;
//vectorWithCoordinates should now contain {123, 456}
return 0;
}
However, when I run this code, I get an error message saying:
terminate called after throwing an instance of "std::invalid argument"
#include <iostream>
#include <string>
#include <vector>
std::vector<int> getCoordinates(std::string string){
auto count = 0;
std::string coordinates;
int coordinatesInt;
std::vector<int> vector;
for(unsigned i = 0; i < string.size(); i++){
if(string.at(i) == ' '){
count++;
unsigned j = 1;
while(i+j<string.size() && string.at(i+j) != ' '){ //checks that you do not go out of range before checking the content of the string
coordinates.push_back(string.at(i+j));
j++;
}
coordinatesInt = std::stoi(coordinates);
vector.push_back(coordinatesInt);
}
coordinates.clear();//clears the string in order to have two different integers
}
if(count != 2){
vector.clear();
}
std::cout << count << std::endl;
return vector;
}
int main()
{
std::string coordinates = "COORDINATES 123 456";
std::vector<int> vectorWithCoordinates = getCoordinates(coordinates);
for(auto i : vectorWithCoordinates)
std::cout<<i<<"\n";
//vectorWithCoordinates should now contain {123, 456}
return 0;
}
The problem in the code was that you tried to access the content of the string at position i+j without being sure that that position is not out of range. I made minimal modifications to your code to obtain the right output (I think).

How to turn an int into a string?

I've been trying to find how to do it online. I'm restricted from not using ready-made functions, like to_string or boost::lexical_cast, not even the <sstream> library. How can I do it with these limitations?
Here's one way to do it:
std::string int_to_string (int i)
{
bool negative = i < 0;
if (negative)
i = -i;
std::string s1;
do
{
s1.push_back (i % 10 + '0');
i /= 10;
}
while (i);
std::string s2;
if (negative)
s2.push_back ('-');
for (auto it = s1.rbegin (); it != s1.rend (); ++it)
s2.push_back (*it);
return s2;
}
I avoided using std::reverse, on the assumption that it would be off-limits.
Live demo
You can use '0' + i to get the char value of 0 and offset it. I.e.
#include <cmath>
#include <string>
#include <iostream>
int main() {
int number = 12345678;
int nrDigits = std::log10(number)+1;
std::string output(nrDigits, '0'); // just some initialization
for (int i = nrDigits - 1; i >= 0; i--) {
output[i] += number % 10;
number /= 10;
}
std::cout << "number is " << output << '\n';
}

Finding the total number of repeat strings in a string C++ -- without maps

My program has to find the total number of repeated strings in a string. I cannot use maps or built in string functions other than length()
Example : string input = "Hello hello Hello"
Hello : 2
I am hitting a roadblock with separating the strings by the spaces and reading them. I can't figure out what to write to make that happen.
What I want to do is create a temp string to compare to the next string and if they are equal to store it in a vector and then read from the vector at the end.
What function could I use to do that?
Here is my code below :
#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector <string> mystring;
int numberString(string const&in)
{
int total = 0;
char temp;
for (int i = 0; i < in.length(); i++)
{
temp = in[i];
if (temp == ' ')
total++;
}
total++;
return total;
}
void findRepeats(string const &in)
{
int numberOfStrings = numberString(in);
int asciiArray[256];
for (int i = 0; i < 256; i++)
asciiArray[i] = 0;
int counter = 0;
string temp = "blank";
while (numberOfStrings != counter)
{
temp = in;
}
}
int main()
{
string input;
cout << "Enter a string : ";
getline(cin, input);
findRepeats(input);
return 0;
}
The straightforward way to count substrings in a whitespace-separated string is to insert them into a map and and track the occurrence count:
std::string input = "Hello hello Hello";
std::istringstream iss(input);
std::map<std::string, size_t> m;
std::string temp;
while(iss >> temp)
{
auto it = m.find(temp);
if(it != std::end(m))
{
++(it->second);
}
else
{
m.insert(std::make_pair(temp, 0));
}
}
//display counts as:
for(auto it = std::begin(m); it != std::end(m); ++it)
{
std::cout<<"string \""<<it->first<<"\" was found "<<it->second<<" times"<<std::endl;
}
The code is untested.
The following code finds duplicate words as long as all words are seperated by a single space:
#include <string>
#include <map>
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
string input = "Hello hello hello";
map<string, int> wordCount;
for (string::size_type p = 0; p < input.size(); )
{
const auto p2 = input.find_first_of(' ', p);
const auto word = input.substr(p, (p == string::npos) ? string::npos : (p2 - p));
++wordCount[word];
if (p2 == string::npos)
break;
p = p2 + 1;
}
for (const auto& it : wordCount)
if (it.second > 1)
std::cout << it.first << " " << it.second << std::endl;
return 0;
}
Be aware that this code does not only find consecutive duplicates. So "a b a" outputs 'a 2'.
The line ++wordCount[word] increments the counter for the word or initializes it to 1 if 'word' is not already found in the map (This is working because the template initializes the value with int() which is guaranteed to initialize to zero)
At the end you get a map with an entry for every unique word (first=Word, second=count)
If you would like to count only consecutive duplicates this piece of code may help you:
#include <string>
#include <map>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string input = "Hello hello hello Hello";
vector<pair<string, int>> wordCount;
for (string::size_type p = 0; p < input.size(); )
{
const auto p2 = input.find_first_of(' ', p);
const auto word = input.substr(p, (p == string::npos) ? string::npos : (p2 - p));
if (wordCount.empty() || wordCount.back().first != word)
wordCount.push_back(make_pair(word, 1));
else
++wordCount.back().second;
if (p2 == string::npos)
break;
p = p2 + 1;
}
for (const auto& it : wordCount)
if (it.second > 1)
std::cout << it.first << " " << it.second << std::endl;
return 0;
}
This code does not use a map because a single word can have different counts depending on its location ("a a b a a a" would output "a 2" and "a 3")
Both examples scan the string word by word with ' ' as the delimiter. You could specify multiple delimiters in find_first_of if you would like to split your string by tab or dot. (input.find_first_of(" \t.", p))

c++ vector size and capacity outputting same value

when I was researching vectors, I noticed that size() is supposed to give the number of elements in the vector, right? So, when I found c++ does not have a string split() function built-in, I decided to make one. The problem is, vector.size() displays the same value as vector.capacity() as shown in the code:
#include <iostream>
#include <algorithm>
using namespace std;
void split(string input, char chr, vector<string> list) {
string add;
string conv;
int size = 0;
for (int i = 0; i <= input.size(); i++) {
if ((input[i] != char(chr)) && (input[i] != 0)) {
conv = input[i];
add += conv;
}
else {
cout << list.size() << endl;
if (size <= list.capacity()) {
list[size] = add;
add = "";
size++;
}
}
}
}
int main() {
vector<string> list(6);
split("test1,test2", ',', list);
for (int i = 0; i < 2; i++) {
cout << list[i] << endl;
}
}
The output is this:
6
6
<blank line>
<blank line>
whereas it SHOULD be this from my understanding:
1
2
test1
test2
Edit: if this is of any importance, I am compiling with -std=c++11
You initialize the vector with size 6, not capacity 6. It will be constructed with 6 empty elements inside and thus setting values 0 and 1 won't change that.
The reason why you see only blank lines is that you pass the vector by value instead of by reference to you split function.
#include <iostream>
#include <string>
#include <vector>
void split (const std::string& s, char sep, std::vector<std::string>& words)
{
if (s.empty()) return;
std::size_t beg = 0;
std::size_t end = s.find(sep, beg);
while (end != std::string::npos)
{
words.push_back(s.substr(beg, end - beg));
beg = end + 1;
end = s.find(sep, beg);
}
words.push_back(s.substr(beg));
}
int main() {
std::vector<std::string> words;
split("test1,test2", ',', words);
for (std::size_t i = 0; i != words.size(); ++i) {
std::cout << words[i] << std::endl;
}
return 0;
}