Fix/Improve Word Wrap Function - c++

I have a simple word wrap function that takes a long string as an input and then breaks that string into smaller strings and adds them to an array to be outputted later. Right now the last word or two isn't outputting. That's the main problem. However, I would also like to improve the function. I know it's kind of messy. I was wondering if there are any better ways of solving this problem. I think the array is unnecessary but I don't know how else to do it. After the array is filled with all the smaller strings, I just output them to a text file. Any suggestions would be greatly appreciated.
Here's the Word Wrap function:
void WordWrap(string inputString, string formatedAr[], const int SIZE)
{
unsigned int index;
unsigned int word;
unsigned int max = 65;
string outWord;
string outLine;
outWord = "";
outLine = "";
word = 0;
for(int i = 0; i < SIZE; i++)
{
formatedAr[i] = "";
}
for(index = 0; index <= inputString.length(); index++)
{
if(inputString[index] != ' ')
{
outWord += inputString[index];
}
else
{
if(outLine.length() + outWord.length() > max)
{
formatedAr[word] = outLine;
word++;
outLine.clear();
}
outLine += outWord + " ";
outWord.clear();
}
}
formatedAr[word] = outLine;
}
And this is where I call the function and output the array:
WordWrap(dvdPtr -> synopsis, formatedAr, SIZE);
index = 0;
while(index < SIZE && formatedAr[index] != "")
{
outFile << formatedAr[index] << endl;
index++;
}

Here is an example code.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
void WordWrap(const string& inputString, vector<string>& outputString, unsigned int lineLength)
{
istringstream iss(inputString);
string line;
do
{
string word;
iss >> word;
if (line.length() + word.length() > lineLength)
{
outputString.push_back(line);
line.clear();
}
line += word + " ";
}while (iss);
if (!line.empty())
{
outputString.push_back(line);
}
}
/*
A simple test:
Input string: "aaa bbb ccccccc dddd d111111111111111 33333 4444444444 222222222 ajdkjklad 341343"
Length per line: 20
Output lines of strings:
Line 1: aaa bbb ccccccc dddd
Line 2: d111111111111111
Line 3: 33333 4444444444
Line 4: 222222222 ajdkjklad
*/

Related

Insert spaces into a string

I have a string and I want to insert spaces between the digits.
Example:
Input String: 123456
Output String: 1 2 3 4 5 6
You could just call the string as an array
std::string str = "123456";
std::string new_string = "";
int string_length = 6;
for(int i=0; i<string_length; i++){
new_string += str[i];
if(i != string_length-1) { new_string += " "; }
}
There are more efficient ways to do it, but this illustrates the behavior in an easily understandable way, with little steps at a time.
With range-v3 you could do:
namespace rv = ranges::views;
auto res = s | rv::intersperse(' ') | ranges::to<std::string>;
Here's a demo.
Best way is to implement your own custom split function.
Have a look at the following implementation:
#include <iostream>
#include <string>
bool isDigit(char c){
return (c>='0' && c<='9');
}
std::string splitOnDigits(std::string s){
std::string out = "";
for(int i=0;i<s.length();i++){
if(isDigit(s[i-1]) || (!isdigit(s[i-1]) && isDigit(s[i]))){
out += " ";
}
out += s[i];
}
return out;
}
int main()
{
std::string s = "123456";
std::cout<<splitOnDigits(s)<<std::endl;
return 0;
}
Output:
1 2 3 4 5 6

How to fill an array with a sentence?

For instance i have the sentence " I am Piet". I want to fill this sentence into an array in a way that I[0], am[1] Piet[2]. Below is the code i've made. The problem is that the sentence is filled in each element of the array.
#include <iostream>
#include <string>
using namespace std;
// function to populate my array
void populateMyArray(string*myArray, string sentence, int size)
{
for (int i = 0; i < size; i++)
{
*myArray = sentence;
myArray++;
}
}
// function to count works in the sentence
int countWords(string x)
{
int Num = 0;
char prev = ' ';
for (unsigned int i = 0; i < x.size(); i++) {
if (x[i] != ' ' && prev == ' ') Num++;
prev = x[i];
}
return Num;
}
int main()
{
string sentence1;
cout << "Please enter a line of text:\n";
getline(cin, sentence1);
int nWords1 = countWords(sentence1);
string *arr1 = new string[nWords1];
populateMyArray(arr1, sentence1, nWords1); //populate array1
for (int i = 0; i < nWords1; i++)
{
cout << "sentence one: " << arr1[i] << "\n";
}
system("PAUSE");
}
You can use vector in order to save data and each time you should use space between two words and you will store each string type into vector array
#include<bits/stdc++.h>
using namespace std;
main()
{
string s;
getline(cin,s);
vector<string> ss;
string temp = "";
s +=" ";
for(int i = 0 ; i < s.size();i ++){
if(s[i] != ' ')
temp += s[i];
else{
ss.push_back(temp);
temp = "";
}
}
for(int i = 0 ; i < ss.size();i ++)
cout << ss[i] <<" ";
}
Instead of using an array, use a std::vector instead. This way you don't have to worry about variable word sizes or overflowing anything in case a word or sentence is too long. Rather you can just do something like this:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main() {
// Get all words on one line
std::cout << "Enter words: " << std::flush;
std::string sentence;
getline(std::cin, sentence);
// Parse words into a vector
std::vector<std::string> words;
std::string word;
std::istringstream iss(sentence);
while( iss >> word ) {
words.push_back(word);
}
// Test it out.
for(auto const& w : words) {
std::cout << w << std::endl;
}
}
For an example sentence of I like cats and dogs equally you will have: words[0] = I, words[1] = like and so on.
If I understood correctly you are trying to split the input sentence into words.
You could do it like this:
void populateMyArray(string *myArray, string sentence, int size)
{
int firstCharIndex = -1;
char prev = ' ';
for (unsigned int i = 0; i < sentence.size(); i++) {
// Find the first character index of current word
if (sentence[i] != ' ' && prev == ' ') {
firstCharIndex = i;
}
// Check if it's the end of current word
// and get substring from first to last index of current word
else if (sentence[i] == ' ' && prev != ' ') {
*myArray = sentence.substr(firstCharIndex, i - firstCharIndex);
myArray++;
}
prev = sentence[i];
}
// For the last word
if (firstCharIndex != -1 && sentence[sentence.size() - 1] != ' ') {
*myArray = sentence.substr(firstCharIndex, sentence.size() - firstCharIndex);
}
}
How to think like a programmer.
The first thing we need is definitions of the beginning or a word and the end of a word. You might think that the beginning of a word is a non-space preceded by a space and the end of a word is a non-space followed by a space. But those definitions are wrong because they ignore the possibility of words at the start or end of the string. The correct definition of the beginning of a word is a non-space at the start of the string or a non-space preceded by a space. Similarly the end of a word is a non-space at the end of the string or a non-space followed by a space.
Now we have the definitions we capture them in two functions. It's very important to break complex problems down into smallier pieces and the way to do that is by writing functions (or classes).
bool beginning_of_word(string str, int index)
{
return str[index] != ' ' && (index == 0 || str[index - 1] == ' ');
}
bool end_of_word(string str, int index)
{
return str[index] != ' ' && (index == str.size() - 1 || str[index + 1] == ' ');
}
Now we're getting closer, but we still need the idea of finding the next start of word, or the next end of word, so we can loop through the sentence finding each word one at a time. Here are two functions for finding the next start and next end of word. They start from a given index and find the next index that is the start or end of a word. If no such index is found they return -1.
int next_beginning_of_word(string str, int index)
{
++index;
while (index < str.size())
{
if (beginning_of_word(str, index))
return index; // index is a start of word so return it
++index;
}
return -1; // no next word found
}
int next_end_of_word(string str, int index)
{
++index;
while (index < str.size())
{
if (end_of_word(str, index))
return index; // index is an end of word so return it
++index;
}
return -1; // no next word found
}
Now we have a way of looping through the words in a sentence we're ready to write the main loop. We use substr to break the words out of the sentence, substr takes two parameters the index of the start of the word and the length of the word. We can get the length of the word by substracting the start from the end and adding one.
int populateMyArray(string* array, string sentence)
{
// find the first word
int start = next_beginning_of_word(sentence, -1);
int end = next_end_of_word(sentence, -1);
int count = 0;
while (start >= 0) // did we find it?
{
// add to array
array[count] = sentence.substr(start, end - start + 1);
++count;
// find the next word
start = next_beginning_of_word(sentence, start);
end = next_end_of_word(sentence, end);
}
return count;
}
Now for extra credit we can rewrite countWords using next_beginning_of_word
int countWords(string sentence)
{
int start = next_beginning_of_word(sentence, -1);
int count = 0;
while (start >= 0)
{
++count;
start = next_beginning_of_word(sentence, start);
}
return count;
}
Notice the similarity of the countWords and the populateMyArray functions, the loops are very similar. That should give you confidence.
This is the way programmers work, when you have a problem that is too complex for you to handle, break it down into smaller pieces.

C++: Reading lines of integers from cin

As I'm familiarizing myself with the I/O aspect of C++, I'm trying to write a program to read some lines of integers from std::cin. Say the input looks like this:
1 2 3
4 5 6
7 8 9
10 11 12
How can I read the above lines into a 2D vector?
vector<vector<int>> nums;
/*
... some code here and nums will look like the following:
nums = {
{1,2,3},
{4,5,6},
{7,8,9},
{10,11,12}
}
*/
I've also tried to read the above lines of integers to a 1D vector, but I'm having some issues dealing with the '\n' character. My code is:
string rawInput;
vector<int> temp;
while(getline(cin, rawInput, ' ') ){
int num = atoi( rawInput.c_str() );
temp.push_back(num);
}
And the final result I got by printing out all the elements in the "temp" vector is:
1 2 3 5 6 8 9 11 12 // 4, 7, 10 went missing
Any help is appreciated. Thank you.
First use getline to grab an entire line, then you can use a istringstream to create a stream of ints just for that line.
At that point it's just a matter of creating each subvector of ints using the vector constructor that takes two iterators. An istream_iterator<int> on your istringstream gets this done:
std::vector<std::vector<int>> nums;
std::string line;
while (std::getline(std::cin, line)) {
std::istringstream ss(line);
nums.emplace_back(std::istream_iterator<int>{ss}, std::istream_iterator<int>{});
}
What is happening is since you are using only ' '(space) as deliminator, the input happens to be
1
2
3\n4 //<------ Newline also comes with the input
...
So, you are passing 3\n4, 6\n7 etc to atoi it returns 3,6 etc(atoi parses the input till first non-digit input) and the 4,7 is lost.
To achieve want you want you can use getline with istringstream (keeping the default deliminator as newline)
string rawInput;
vector<vector<int>> temp;
while(getline(cin, rawInput) ){
istringstream bufferInput(rawInput);
temp.push_back(vector<int>{std::istream_iterator<int>{bufferInput}, std::istream_iterator<int>{}});
}
you can use stringstream
string rawInput;
vector<int> temp;
stringstream ss;
while(getline(cin,rawInput)){
ss<<rawInput;
vector<int> temp;
int x;
while(ss>>x){
temp.push_back(x);
}
num.push_back(temp)
}
I recently wrote an answer to another question but with a few adaptations it achieves exactly what you are looking for (I hope):
#ifndef _IOSTREAM_H
#include <iostream>
#endif
#ifndef _STRING_H
#include <string>
#endif
#ifndef _VECTOR_H
#include <vector>
#endif
using namespace std;
enum XYZ { X = 0, Y = 1, Z = 2 };
struct Vector {
float x, y, z;
Vector(float _x=0, float _y=0, float _z=0) {
x = _x;
y = _y;
z = _z;
}
float& operator[](size_t index) {
if (index == XYZ::X) return x;
if (index == XYZ::Y) return y;
if (index == XYZ::Z) return z;
throw new exception;
}
};
#define min(a, b) (((a) < (b)) ? (a) : (b))
bool isCharNumeric(char c) {
const char* numbers = "0123456789";
for (size_t index = 0; index < strlen(numbers); index++)
if (c == numbers[index]) return true; return false;
}
vector<Vector> parseNumbers(string str_in) {
str_in += " "; //safe, no out of bounds
vector<Vector> results = {};
char currentChar;
char skipChar = ' ';
bool found_period = false;
size_t count_len = 0;
Vector vector_buffer(0,0,0);
XYZ current_axis = (XYZ)0;
for (size_t index = 0; index < str_in.length(); index++) {
currentChar = str_in[index];
if (currentChar == skipChar || currentChar == '\n' || currentChar == '\t')
continue;
else if (isCharNumeric(currentChar)) {
string word = ""; //word buffer
size_t word_len = min(min(str_in.find_first_of(' ', index + 1) - (index), str_in.find_first_of('\n', index + 1) - (index)), str_in.find_first_of('\t', index + 1) - (index)); //whatever char comes first; newline, tab or space
//append chars of following word checking if it is still valid number char
if (word_len > 0) {
size_t count_word_len = 0;
for (count_word_len = 0; count_word_len < word_len; count_word_len++)
if (isCharNumeric(str_in[index + count_word_len])) {
word += str_in[index + count_word_len];
}
else if (str_in[index + count_word_len] == '.' && isCharNumeric(str_in[index + count_word_len + 1])) {
//Floating-point numbers
word += '.';
found_period = true;
continue;
}
else {
word = "";
continue;
}
vector_buffer[current_axis] = stof(word);
if (current_axis == XYZ::Z) {
current_axis = XYZ::X;
results.push_back(vector_buffer);
}
else {
current_axis = (XYZ)(current_axis + 1);
}
index += count_word_len;
word = "";
continue;
}
}
}
return results;
}
Example implementation:
int main(int argc, char** argv) {
string user_input;
cin >> user_input;
vector<Vector> numbers = parseNumbers(user_input);
for each (Vector v in numbers) {
cout << "X=" << v.X << "\n";
cout << "Y=" << v.Y << "\n";
cout << "Z=" << v.Z << "\n\n";
}
}
Suprisingly none of the answers use the istream stream operator:
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
When stream is empty eofbit is set, so run a while loop on that.
Works great for all types, and can be overloaded for custom types (such as 2D texture).

Taking Multiple inputs in C++

I just began learning C++ and had a rookie question.
Suppose I am given an input separated by spaces ex 2 4 56 or 2 1 10 15 or hi bye ok.
How can I store the values in an array as the length of input is not know.
Read up on std::vector. It can grow to the size needed.
search for spaces and split the string in each space as the following
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> GetInputs(string s)
{
vector<size_t> foundSpacesPositions;
vector<string> results;
for (size_t i = 0; i < s.length(); i++)
{
if (isspace(s[i]))
{
foundSpacesPositions.push_back(i);
}
}
size_t start = 0;
for (size_t i = 0; i < foundSpacesPositions.size(); i++)
{
if (foundSpacesPositions[i] == start)
{
++start;
continue;
}
results.push_back(s.substr(start, foundSpacesPositions[i] - start));
start = foundSpacesPositions[i] + 1;
}
if (start < s.length() - 1)
results.push_back(s.substr(start, s.length() - 1));
return results;
}
int _tmain(int argc, _TCHAR* argv[])
{
string s = "a dd 8 ll ehh fd $%^ & 89 . ";
vector<string> results = GetInputs(s);
for (auto& res : results)
{
cout << res << endl;
}
cin.get();
return 0;
}
/* OUTPUT
a
dd
8
ll
ehh
fd
$%^
&
89
.
*/
Well, if the input is given as a string, you can easily use a std::istringstream. If the input is given in stdin, you can just use the std::cin stream. std::istream's operator<< will take integers from a string using spaces as a default delimiter. Once you've read all the input on the stream, std::istream's operator bool will return false, and you can stop reading.
An example implementation would be:
vector<int> getIntsFromString(const string& s) {
istringstream ss(s);
int i;
vector<int> result;
while (ss >> i) result.push_back(i);
return move(result);
}
Suppose you are getting multiple lines with a variable number of integers from stdin, and you want to store them in vector<int>'s. You can do something similar to:
string buf;
while (getline(cin, buf)) {
auto v = getIntsFromString(buf);
for (auto i : v) cout << i << ' ';
cout << endl;
}

Print duplicates of strings

I am working a code that will find the amount of duplicated words from a imported file.
The input stream represents a file containing a series of lines. The function should
examine each line looking for consecutive occurrences of the same token on the same line and
print each duplicated token along how many times it appears consecutively. Non-repeated
tokens are not printed.
Here is what I have:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
ifstream in("file.txt");
if (! in)
{
cerr << "Could not open file.txt.";
return EXIT_FAILURE;
}
string str;
int count = 0;
int len=str.length();
while(getline(in,str)){
for(int i = 0; i < len; i++){
if(str.at(i) == str.at(i+1)){
count++;
}
else if(str.at(i) != str.at(i+1)){
i++;
}
}
cout << str << "*" << count << endl;
}
}
The .txt contains:
hello how how are you you you you
I I I am Jack's Jack's smirking smirking smirking smirking smirking revenge
bow wow wow yippee yippee yo yippee yippee yay yay yay
one fish two fish red fish blue fish
It's the Muppet Show, wakka wakka wakka
The output should be:
how*2 you*4
I*3 Jack's*2 smirking*5
wow*2 yippee*2 yippee*2 yay*3
wakka*3
a=list('this is my laptop')
b=list(set(a))
for i in b:
if i==' ':
continue
c=a.count(i)
if c>1:
print('{} is {}'.format(i,c))
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
ifstream in("file.txt");
if(!in){
cerr << "Could not open file.txt.";
return EXIT_FAILURE;
}
string str;
string str2;
string n;
string tab[100];
string tab3[100];
unsigned int tab2[100];
unsigned int tab4[100];
unsigned int i = 0;
unsigned int k = 0;
unsigned int l = 0;
unsigned int tablenght;
unsigned int tablenght2;
k = 0;
//it reads every line of text in file str2
while(getline(in,str2)){
//it add every line of text str2 to str so you get whole file text
str += str2;
str += ' ';
//you need to add a character to mark where was the new line
str += "0 ";
}
for(i = 0; i < str.length(); i++){
/*you check every single character in string str if that char is not
space than it writes it to string table tab, if that char is space than it
adds one to your index so it will write down the next word in next
index of table tab*/
if(str[i] != ' '){
tab[k] += str[i];
}else{
k++;
//that is for two spaces
if(str[i+1] == ' '){
k--;
}
}
}
//k+1 is actually how many words and indexes you wrote to table tab
tablenght = k+1;
l = 0;
k = 0;
for(i = 0; i < tablenght; i++){
//you need to reset the number of repeats k to zero if you go to another line
if(tab[i] == "0"){
k = 0;
}
//there you get the number k how many times does some word repeats itself
if(tab[i] == tab[i+1]){
k++;
//you need to reset k if tab current is not equal to tab next
}else{
k = 0;
}
//there you store k values into integer table tab2
tab2[l] = k+1;
l++;
}
l = 0;
/*there you need to check if current string of table tab is equal to next string
in table tab and if it is you need to set next string to tab3[l] if you dont do
that you get something like that you*4 you*4 you*4 you*4 instead of only you*4*/
for(i = 0; i < tablenght-1; i++){
if(tab[i] == tab[i+1]){
tab3[l] = tab[i+1];
tab4[l] = tab2[i];
}else{
l++;
}
if(tab[i+1] == "0"){
tab3[l] = tab[i+1];
}
k++;
}
tablenght2 = l;
//there you cout both tables
for(i = 0; i < tablenght2; i++){
/*you need to check if number is bigger than 1 because it need to cout only
the words that repeats itself for more than one time than you need to check
that table tab3 doesnt contain string with zero that we previously added
that we could check later if it needs to go in another line and we
need to check that tab3 index is not empty*/
if(tab4[i] > 1 && tab3[i] != "0" && !tab3[i].empty()){
cout << tab3[i] << "*" << tab4[i] << " ";
}
/*thats the zero that we wrote to table in the begining and that we can now
write a new line*/
if(tab3[i] == "0"){
cout << endl;
}
}
return 0;
}