C++ Multiple delimiters with more than one char - c++

In c++, I'm having trouble coding multiple delimiters with single char delimiters and string delimiters (e.g. "<=" as a delimiter as opposed to '='). The code below works with single char delimiters (I've set the delimiters as space, comma, dot, plus and equal) and separates the words in string line nicely. However, I don't know how to add string delimiters to this code.
std::string delimiters = " ,.+=";//I want "<=" added as a single delimiter
std::string line = "this+is,a.string=testing one";
std::size_t prev = 0, pos;
while ((pos = line.find_first_of(delimiters, prev)) != std::string::npos)
{
if (pos > prev)
{
cout << line.substr(prev, pos-prev) << endl;
prev = pos + 1;
}
}
if (prev < line.length()){
cout << line.substr(prev, std::string::npos) << endl;
}

Here is one way you could do it by erasing the delimiters you find from the line_copy string, having a special if statement for the special delimiter. Full example here:
auto pos = find_first_of(begin(line_copy), end(line_copy), begin(delimiters),
end(delimiters));
while (pos != line_copy.end()) {
if (pos != line_copy.end()) {
if (*pos == '<' && *(pos + 1) == '=') {
cout << "delimiter: \'";
cout << string(pos, pos + 2) << "\'" << endl;
// remove the delimiters from copy string
line_copy.erase(pos, pos + 2);
}
else {
cout << "delimiter: \'" << *pos << "\'" << endl;
// remove the delimiters from copy string
line_copy.erase(pos, pos + 1);
}
}
cout << endl;
pos = find_first_of(begin(line_copy), end(line_copy), begin(delimiters),
end(delimiters));
}

I would change the line
rev = pos + 1
in the following way:
if (pos > prev)
{
cout << line.substr(prev, pos-prev) << endl;
prev = line.find_first_not_of(delimiters, pos))
}
So once you hit a delimiter then you move to the fiurst char not being a delimiter.

Do a two character search one by one.
Search for "<" first and if found search for an immediate "=" if found, do substr otherwise continue searching.

Related

Trying to find the number of words without counting the spaces

I am trying to find the number of words in from the input by user but i am asked not to find it through counting the spaces since the user can input a single letter and a bunch of spaces and it will count it as number of words
I have tried it with counting the number of spaces but i can not think of another way to count the number of words
char Array[100];
{
//variable declaration
int words = 0;
// input
cout << "Enter string: ";
cin.getline(Array, 100);
// Number of words
for (int i = 0; i < strlen(Array); i++)
{
if (Array[i] == ' ')
words++;
}
cout << "Number of words in the string are: " << words + 1;
cout << endl;
}
I want to find the number of words with another method rather than counting it through the number of spaces.Any help is appreciated.I am a beginner so could you not use something complicated to solve the problem like a getloc.
You just have to count the number of times the space character is followed immediately by a non-space character.
int firstNonSpace = 0;
while (Array[firstNonSpace] == ' ') //to skip spaces at the beginning of input
{
firstNonSpace++;
}
for (int i = firstNonSpace; i < strlen(Array) - 1; i++)
{
if (Array[i] == ' ' && Array[i+1] != ' ')
words++;
}
if(words || firstNonSpace == 0)
words++; //do not increment if the input is empty or only spaces.
cout << "Number of words in the string are: " << words;
See Live Demo
Note that you will have to handle the case when the input exceeds the bounds of the array so as not to run into undefined behavior.
The easiest way is to let the standard library parse the words for you, eg:
#include <iostream>
#include <string>
#include <sstream>
int main () {
//variable declarations
std::string line, word;
int words = 0;
// input
std::cout << "Enter string: ";
std::getline(std::cin, line);
// Number of words
std::istringstream iss(line);
while (iss >> word) {
++words;
}
std::cout << "Number of words in the string are: " << words << std::endl;
return 0;
}
If you don't want to use std::string (ie, to avoid memory allocations), you could do this instead:
#include <iostream>
#include <algorithm>
#include <cctype>
int main() {
//variable declarations
char Array[100];
int words = 0;
// input
std::cout << "Enter string: ";
std::cin.getline(Array, 100);
// Number of words
char *ptr = Array;
char *end = ptr + std::cin.gcount();
while (ptr != end) {
ptr = std::find_if(ptr, end, [](char c){ return !std::isspace(static_cast<unsigned char>(c)); });
if (ptr == end) break;
ptr = std::find_if(ptr+1, end, [](char c){ return std::isspace(static_cast<unsigned char>(c)); });
++words;
}
std::cout << "Number of words in the string are: " << words << std::endl;
return 0;
}
Or, if you want to completely avoid standard library algorithms:
#include <iostream>
int main() {
//variable declarations
char Array[100];
int words = 0;
// input
std::cout << "Enter string: ";
std::cin.getline(Array, 100);
// Number of words
char *ptr = Array;
char *end = ptr + std::cin.gcount();
while (ptr != end) {
while ((*ptr <= ' ')) && (ptr != end)) ++ptr;
if (ptr == end) break;
++ptr;
while ((ptr != end) && (*ptr > ' ')) ++ptr;
++words;
}
std::cout << "Number of words in the string are: " << words << std::endl;
return 0;
}
You could then wrap the parsing into a helper function to clean up the counting loop:
#include <iostream>
//#include <algorithm>
//#include <cctype>
bool findNextWord(char* &begin, char *end) {
/*
begin = std::find_if(begin, end, [](char c){ return !std::isspace(static_cast<unsigned char>(c)); });
if (begin == end) return false;
begin = std::find_if(begin+1, end, [](char c){ return std::isspace(static_cast<unsigned char>(c)); });
return true;
*/
while ((begin != end) && (*begin <= ' ')) ++begin;
if (begin == end) return false;
++begin;
while ((begin != end) && (*begin > ' ')) ++begin;
return true;
}
int main() {
//variable declarations
char Array[100];
int words = 0;
// input
std::cout << "Enter string: ";
std::cin.getline(Array, 100);
// Number of words
char *ptr = Array;
char *end = ptr + std::cin.gcount();
while (findNextWord(ptr, end)) {
++words;
}
std::cout << "Number of words in the string are: " << words << std::endl;
return 0;
}
Just do the following change and bob's your uncle :)
if(array[i] == ' ') {
continue;
}
words++;
while(array[i] != ' ') {
i++;
}
I was looking online and found them all very confusing this is simple and works
string state;//variable for statement the user may enter
int i; //variable for the for loop
int wordtally; // variable for word count
//this checks if its a space or not and then if it is a space it loops untill it
//reaches a character then after reaching a character loops until it hits a space anmd
//when that happens the counter goes up making it so every time a blank amount of spaces
//then a word it increases word count
for ( i=0 ; i < state.length() ; i++ )
{
if(state[i]==' '){
do {
i++;
}while(state[i]==' ');
}
else if(state[i]>=' '){
do {
i++;
}
while(state[i]>' ');
wordtally++ ;
}
}

Comparing two string iterators always comes out true C++

So, here's a bit of an odd question that I'm really just having trouble with. I have a list of strings and I'm trying to see if two of them match. So, I have one iterate through and get each string, and another that checks if it has a match. However, it always says that the two are true - even when the first doesn't have a match in the list.
for(iterator = tagList.begin(); iterator != tagList.end(); ++iterator)
{
string theWord = *iterator;
string currentWord = *iterator;
if(currentWord[0] == '<' && currentWord[1] != '/')
{
bool matchFound = false;
list<string>::const_iterator it2;
for(it2 = (++iterator); it2 != tagList.end(); ++it2)
{
string temp = *it2;
if(currentWord.compare(temp) && temp != "")
{
fixedString += theWord + ' ';
matchFound = true;
cout << "A match was found... Current string: "
<< fixedString << endl;
cout << "\tthe matched word was " << *it2 << endl;
break;
}
}
if(!matchFound)
{
currentWord = *iterator;
currentWord = currentWord.substr(1, currentWord.size() - 2);
fixedString += currentWord;
cout << "No match was found... Current string: " << fixedString
<< endl;
}
}
}
Any ideas on why it's always true?
Your problem is with currentWord.compare(temp). string::compare() has a return type of int that will be 0 if they are equal (which evaluates to false) and a positive or negative numerical value if they are different (which evaluates to true).
You want:
if((currentWord.compare(temp) == 0) && temp != "") {
...
You can read about string::compare() here:
http://www.cplusplus.com/reference/string/string/compare/

using str::find and find_first_of and last_of

Im not sure if I used find_first of and last_of correctly, but what I want to do is that I need to print error when it finds _ on the beginning or at the end of my code, plus when it finds two or more _ next to each other, like this lol___, lol__lol, _lol_, _lol, lol_, and one more rule, _ cannot be in front of capital letter, like this lol_Lol
here is my code
std::string::size_type n;
std::string::size_type n2;
std::string::size_type n3;
std::string const ss = slovo;
n = ss.find('_');
n2 = ss.find_first_of('_');
n3 = ss.find_last_of('_');
if (n2 == std::string::npos && n3 == std::string::npos) {
cout << "chyba" << endl;
}else if(n == std::string::npos){
string s = transform(slovo);
cout << s << endl;
}else{
string s = untransform(slovo);
cout << s << endl;
}
EDIT>
if ( !ss.empty() && ss.front() == '_' && ss.back() == '_' )
{
cout << "Chyba" << endl;
} else {
if ( ss.length() > 3 && ss.find( '__', 1, ss.length() - 2 ) != std::string::npos )
{
if (n == std::string::npos){
string s = transform(slovo);
cout << s << endl;
}else{
string s = untransform(slovo);
cout << s << endl;
}
}else{
cout << "chyba" << endl;
}
}
EDIT2:
cin >> slovo;
}
std::string::size_type n;
std::string const ss = slovo;
n = ss.find('_');
// kontrola podtrznika
if ( ss.empty() && ss[0] == '_' && ss[ss.length() - 1] == '_' )
{
cout << "chyba" << endl;
}
if ( ss.length() > 3 && ss.find( "__", 1, ss.length() - 2 ) != std::string::npos )
{
cout << "chyba" << endl;
}
if (n == std::string::npos)
{
string s = transform(slovo);
cout << s << endl;
}else{
string s = untransform(slovo);
cout << s << endl;
}
if those functions return npos it means the character couldn't be found in the string. So if one of them returns that, all 3 of them will.
So this code outputs 'chyba' it there's no _ in the string or calls untransform otherwise. From your description, that's not what you intend.
You really need to scan through the string for all those conditions. And if you want to check the first and last characters of the string, use ss[0] and ss[ss.length() - 1] (taking appropriate care you don't have a string of length 0 or 1).
It is obvious that the two function calls will give you the same result
n = ss.find('_');
n2 = ss.find_first_of('_');
In this context they are equivalent.
If I have understood you correctly you need to determine whether the first and the last characters in a string are underscores and whether the string contains two adjacent undescores within itself.
To determine the first case it is simple to write
if ( !ss.empty() && ss.front() == '_' && ss.back() == '_' )
{
//...
}
To find at least two adjacent underscores excluding the first and the last characters you can write
if ( ss.length() > 3 && ss.find( "__", 1, ss.length() - 2 ) != std::string::npos )
{
//...
}

C++ search for words string

I want to create program which will go through sentence and if it finds a character or a word it will display it.
Think of a program that stops as soon as it find first character/word.
string test("This is sentense i would like to find ! "); //his is sentense to be searched
string look; // word/char that i want to search
cin >> look;
for (i = 0; i < test.size(); i++) //i<string size
{
unsigned searcher = test.find((look));
if (searcher != string::npos) {
cout << "found at : " << searcher;
}
}
You do not need the loop. Just do:
std::cin >> look;
std::string::size_type pos = test.find(look);
while (pos != std::string::npos)
{
// Found!
std::cout << "found at : " << pos << std::endl;
pos = test.find(look, pos + 1);
}
Here is a live example showing the result for the input string "is".

Reading from file and avoiding white space in blank lines

I'm currently working on a project where I'm reading in commands and I need to avoid whitespace on lines that are blank. I've done good up to this point but for some reason I just can't seem to figure out how to make it work. I thought if(opcode == "\t" || opcode == " ")continue; would take care of, but it didn't. If someone could please have a look and help me out that'd be great.
Here's a small sample of the commands I'm reading in. They are in [label] opcode [arg1][,arg2] format.
#Sample Input
LA 1,1
LA 2,2
\t <<<<<<<Here just to show that it's a blank line with only a tab
TOP NOP
Here is my code:
int counter = 0;
int i = 0;
int j = 0;
int p = 0;
while (getline(myFile, line, '\n'))
{
if (line.length() == 0)
{
continue;
}
if (line[0] == '#')
{
continue;
}
// If the first letter isn't a tab or space then it's a label
if (line[0] != '\t' && line[0] != ' ')
{
string delimeters = "\t ";
int current;
int next = -1;
current = next + 1;
next = line.find_first_of( delimeters, current);
label = line.substr( current, next - current );
Symtablelab[i] = label;
Symtablepos[i] = counter;
if(next>0)
{
current = next + 1;
next = line.find_first_of(delimeters, current);
opcode = line.substr(current, next - current);
if (opcode != "WORDS" && opcode != "INT")
{
counter += 3;
}
if (opcode == "INT")
{
counter++;
}
if (next > 0)
{
delimeters = ", \n\t";
current = next + 1;
next = line.find_first_of(delimeters, current);
arg1 = line.substr(current, next-current);
if (opcode == "WORDS")
{
counter += atoi(arg1.c_str());
}
}
if (next > 0)
{
delimeters ="\n";
current = next +1;
next = line.find_first_of(delimeters,current);
arg2 = line.substr(current, next-current);
}
}
i++;
}
// If the first character is a tab or space then there is no label and we just need to get a counter
if (line[0] == '\t' || line[0] == ' ')
{
string delimeters = "\t \n";
int current;
int next = -1;
current = next + 1;
next = line.find_first_of( delimeters, current);
label = line.substr( current, next - current );
if(next>=0)
{
current = next + 1;
next = line.find_first_of(delimeters, current);
opcode = line.substr(current, next - current);
if (opcode != "WORDS" && opcode != "INT")
{
counter += 3;
}
if (opcode == "INT")
{
counter++;
}
if (next > 0)
{
delimeters = ", \n\t";
current = next + 1;
next = line.find_first_of(delimeters, current);
arg1 = line.substr(current, next-current);
if (opcode == "WORDS")
{
counter += atoi(arg1.c_str());
}
}
if (next > 0)
{
delimeters ="\n\t ";
current = next +1;
next = line.find_first_of(delimeters,current);
arg2 = line.substr(current, next-current);
}
}
}
}
Use std::stringstream and read from your line to std::string variables. In this way the blank will be omitted.
[UPDATE]
If you want to remove blank whitespace from the beginning:
s.erase(s.find_last_not_of(" \n\r\t")+1);
[UPDATE2] Or just count words while reading:
Like in this example:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string line;
while (std::getline(std::cin, line))
{
std::string lineNoWS = line;
lineNoWS.erase(lineNoWS .find_last_not_of(" \n\r\t")+1);
if (lineNoWS.empty())
std::cout << "EMPTY LINE\n";
std::string word;
unsigned words = 0;
std::istringstream line_is(line);
while(line_is >> word)
{
std::cout << '\'' << word << "'\n";
++words;
}
std::cout << "(" << words << ")ENDLINE\n";
}
}
Just replace std::cin with your ifstream(file).
You should probably try to make the reading of commands more "generic".
Assuming a line to be valid must start with a label and your labels can only contain "letters", instead of checking for '\t', '\n', '\r', '#', (...)
Why don't you just use the function isalpha ?
Then you need to get the arguments, and assuming they are delimited by ',' your best approach is to split the line according to the ',' delimiter.
Some sample code, that gets you the "label" and a vector with the "arguments", I suggest that you also validate the label (ex. check if the label is only consisted with letters, and assuming that you know the "commands" validate the number and type of arguments that you are retrieving for a specific label.
std::ifstream inStream("c:\\data\\dump.txt");
if(!inStream.fail())
{
while(!inStream.eof())
{
std::string strLine;
std::getline(inStream, strLine);
// Label ?
if( isalpha(strLine[0]))
{
int iIndexOf = strLine.find(" ");
if(iIndexOf != string::npos)
{
std::string strLabel = strLine.substr(0, iIndexOf);
// Arguments ?
std::vector<std::string> vArguments;
std::stringstream ss(strLine.substr(iIndexOf, strLine.size() - iIndexOf));
std::string strArgument;
while(std::getline(ss, strArgument, ','))
{
if(strArgument.size()!=0)
vArguments.push_back(strArgument);
}
std::cout << "label: " << strLabel << std::endl << "arguments list: ";
for(size_t i=0; i<vArguments.size(); i++)
std::cout << vArguments[i] << ";";
std::cout << std::endl;
}
else
{
// No Arguments
std::string strLabel = strLine;
std::cout << "label: " << strLabel << std::endl;
}
}
}
inStream.close();
}