Why does an error occur when I try to test if a member variable (string) in a class is empty? - c++11

I'm working on a project and need to test one of my class' member variables to verify that the user did indeed enter a string.
I've also tried using (patronName == '') and (patronName == "") but have had no luck.
Edit: Using "\n" fixes the error but the program ends without allowing the user to enter a name.
std::string Restaurant::getPatronName()
{
bool controlFlag = true;
do
{
getline(std::cin,patronName);
if ((std::cin.fail()) || (patronName == '\n'))
{
std::cout << "You must enter a name!" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else
{
controlFlag = false;
}
} while (controlFlag);
return patronName;
}
The function should read and store the name entered by the user into patronName. When trying to build, I get an error that says "no match for 'operator=='". Could this be because the object called in main is a pointer of type Restaurant?

Besides the type mismatch between the character '\n' and the std::string patronName, we can find at https://en.cppreference.com/w/cpp/string/basic_string/getline that std::getline(input, str, delim);
Extracts characters from input and appends them to str until […] the next available input character is delim, […], in which case the delimiter character is extracted from input, but is not appended to str.
So there won't be any '\n' character, if delim is the newline, in the first place.
You can use std::basic_string::empty() to check if a string is empty.

What happens with '\n' is you are comparing a string with a char, which, i suspect, there is no operator== defined for this case. If you are sure the string isn't empty, you can call operator[] formerName[0], which returns a char.

You have to write patronName == "\n" because you cannot compare string and character

Related

C++ empty() and all_of() for checking string is empty or have only digit

I'm creating an IO console application and at the inputs i got an 'while' loop with two condition
empty() and all_of(), the function all_of() seems to work properly but when i press enter the empty() function not working and just let me to input the next thing in the 'struct'. I'm not sure am i doing it correct..There is the part of the code
cout << "Enter age: ";
getline(cin, age_str);
while(!age_str.empty() && !all_of(age_str.begin(), age_str.end(), ::isdigit)){
cout << "--Please Enter an integer-- " << endl;
cin.clear();
getline(cin, age_str);
}
stringstream(age_str) >> person_arr[n].age;
There are a link to the full code : enter link description here
The logic of the conditional of the while is incorrect.
What you need to do is:
If the line is empty, get the next line.
If the line is not empty and the line has anything other than digits, get the next line.
!age_str.empty() && !all_of(age_str.begin(), age_str.end(), ::isdigit) does not do that.
You need to use age_str.empty() || (!all_of(age_str.begin(), age_str.end(), ::isdigit))
I always recommend, when in doubt, simplify.
while ( !is_input_valid(age_str)) )
{
...
}
where
bool is_input_valid(std::string const& input)
{
if ( input.empty() )
{
return false;
}
return std::all_of(input.begin(), input.end(), ::isdigit);
}

How to convert string to rapid json value

I am using rapidjson library to encode and deconde the json.
I have received the string lets say string Str = "msisdn-123456789";
i want to covert this into a rapidjson value but it says parsing error. and value type is still kNullType
I am using below code snippest.
std::string Str = "msisdn-123456789";
rapidjson::Document newDoc;
newDoc.Parse(Str.c_str());
rapidjson::Value value(rapidjson::kNullType);
value.CopyFrom(newDoc, newDoc.GetAllocator());
cout << "Type of value" << static_cast<uint32_t>(value.GetType()) << endl;
The output is kNullType (0) .
How can i convert string to rapidjson value ?
std::string Str = "msisdn-123456789"; is not a valid JSON. So parsing it will have an null value at the document root.
For constructing a Value by std::string s, just
Value v(s, allocator); // When RAPIDJSON_HAS_STDSTRING=1
Value v(s.c_str(), s.size(), allocator); // Otherwise

trying the check if cin.get() leaves the end of line character in stream

1.i am trying to check whether the cin.get() leaves the end line character in stream and considered it for next input.
i have tried this code in code blocks but unable to provide input for next string,i am attaching code i have tried and the output .could anyone please explain.
#include<iostream>
using namespace std;
int main()
{
char s1[10];
char s2[10];
cout << "enter the first string: ";
cin.get(s1, 10);
cout << "enter the second string: ";
cin.getline(s2, 10);
cout << s1 << " " << s2;
return 0;
}
enter the first string: hello
enter the second string: hello
please explain the output
This get function reference says that your overload is
Same as get(s, count, widen('\n'))
And that overload of the function reads until (among other things)
the next available input character c equals delim, as determined by Traits::eq(c, delim). This character is not extracted (unlike basic_istream::getline())
[Emphasis mine]
So the newline is left in the input buffer, for the getline call to read as an "empty" line.
If you want to read lines, I suggest you use std::string and std::getline (which does read, and throw away, the newline).
cin.get() grabs the newline character by default. It will not leave the newline in the stream.

split text file according to brackets or parantheses (top-level only) in terminal

I have several text files (utf-8) that I want to process in shell script. They aren't excactly the same format, but if I could only break them up into edible chunks I can handle that.
This could be programmed in C or python, but I prefer not.
EDIT: I wrote a solution in C; see my own answer. I think this may be the simplest approach after all. If you think I'm wrong please test your solution against the more complicated example input from my answer below.
-- jcxz100
For clarity (and to be able to debug more easily) I want the chunks to be saved as separate text files in a sub-folder.
All types of input files consist of:
junk lines
lines with junk text followed by start brackets or parentheses - i.e. '[' '{' '<' or '(' - and possibly followed by payload
payload lines
lines with brackets or parentheses nested within the top-level pairs; treated as payload too
payload lines with end brackets or parantheses - i.e. ']' '}' '>' or ')' - possibly followed by something (junk text and/or start of a new payload)
I want to break up the input according to only the matching pairs of top-level brackets/parantheses.
Payload inside these pairs must not be altered (including newlines and whitespace).
Everything outside the toplevel pairs should be discarded as junk.
Any junk or payload inside double-quotes must be considered atomic (handled as raw text, thus any brackets or parentheses inside should also be treated as text).
Here is an example (using only {} pairs):
junk text
"atomic junk"
some junk text followed by a start bracket { here is the actual payload
more payload
"atomic payload"
nested start bracket { - all of this line is untouchable payload too
here is more payload
"yet more atomic payload; this one's got a smiley ;-)"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
} trailing junk
intermittent junk
{
payload that goes in second output file }
end junk
...sorry: Some of the input files really are as messy as that.
The first output file should be:
{ here is the actual payload
more payload
"atomic payload"
nested start bracket { - all of this line is untouchable payload too
here is more payload
"yet more atomic payload; this one's got a smiley ;-)"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
}
... and the second output file:
{
payload that goes in second output file }
Note:
I haven't quite decided whether it's necesary to keep the pair of start/end characters in the output or if they themselves should be discarded as junk.
I think a solution that keeps them in is more general use.
There can be a mix of types of top-level bracket/paranthesis pairs in the same input file.
Beware: There are * and $ characters in the input files, so please avoid confusing bash ;-)
I prefer readability over brevity; but not at an exponential cost of speed.
Nice-to-haves:
There are backslash-escaped double-quotes inside the text; preferably they should be handled
(I have a hack, but it's not pretty).
The script oughtn't break over mismatched pairs of brackets/parentheses in junk and/or payload (note: inside the atomics they must be allowed!)
More-far-out-nice-to-haves:
I haven't seen it yet, but one could speculate that some input might have single-quotes rather than double-quotes to denote atomic content... or even a mix of both.
It would be nice if the script could be easily modified to parse input of similar structure but with different start/end characters or strings.
I can see this is quite a mouthful, but I think it wouldn't give a robust solution if I broke it down into simpler questions.
The main problem is splitting up the input correctly - everything else can be ignored or "solved" with hacks, so
feel free to ignore the nice-to-haves and the more-far-out-nice-to-haves.
Given:
$ cat file
junk text
"atomic junk"
some junk text followed by a start bracket { here is the actual payload
more payload
"atomic payload"
nested start bracket { - all of this line is untouchable payload too
here is more payload
"yet more atomic payload; this one's got a smiley ;-)"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
} trailing junk
intermittent junk
{
payload that goes in second output file }
end junk
This perl file will extract the blocks you describe into files block_1, block_2, etc:
#!/usr/bin/perl
use v5.10;
use warnings;
use strict;
use Text::Balanced qw(extract_multiple extract_bracketed);
my $txt;
while (<>){$txt.=$_;} # slurp the file
my #blocks = extract_multiple(
$txt,
[
# Extract {...}
sub { extract_bracketed($_[0], '{}') },
],
# Return all the fields
undef,
# Throw out anything which does not match
1
);
chdir "/tmp";
my $base="block_";
my $cnt=1;
for my $block (#blocks){ my $fn="$base$cnt";
say "writing $fn";
open (my $fh, '>', $fn) or die "Could not open file '$fn' $!";
print $fh "$block\n";
close $fh;
$cnt++;}
Now the files:
$ cat block_1
{ here is the actual payload
more payload
"atomic payload"
nested start bracket { - all of this line is untouchable payload too
here is more payload
"yet more atomic payload; this one's got a smiley ;-)"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
}
$ cat block_2
{
payload that goes in second output file }
Using Text::Balanced is robust and likely the best solution.
You can do the blocks with a single Perl regex:
$ perl -0777 -nlE 'while (/(\{(?:(?1)|[^{}]*+)++\})|[^{}\s]++/g) {if ($1) {$cnt++; say "block $cnt:== start:\n$1\n== end";}}' file
block 1:== start:
{ here is the actual payload
more payload
"atomic payload"
nested start bracket { - all of this line is untouchable payload too
here is more payload
"yet more atomic payload; this one's got a smiley ;-)"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
}
== end
block 2:== start:
{
payload that goes in second output file }
== end
But that is a little more fragile than using a proper parser like Text::Balanced...
I have a solution in C. It would seem there's too much complexity for this to be easily achieved in shell script.
The program isn't overly complicated but nevertheless has more than 200 lines of code, which include error checking, some speed optimization, and other niceties.
Source file split-brackets-to-chunks.c:
#include <stdio.h>
/* Example code by jcxz100 - your problem if you use it! */
#define BUFF_IN_MAX 255
#define BUFF_IN_SIZE (BUFF_IN_MAX+1)
#define OUT_NAME_MAX 31
#define OUT_NAME_SIZE (OUT_NAME_MAX+1)
#define NO_CHAR '\0'
int main()
{
char pcBuff[BUFF_IN_SIZE];
size_t iReadActual;
FILE *pFileIn, *pFileOut;
int iNumberOfOutputFiles;
char pszOutName[OUT_NAME_SIZE];
char cLiteralChar, cAtomicChar, cChunkStartChar, cChunkEndChar;
int iChunkNesting;
char *pcOutputStart;
size_t iOutputLen;
pcBuff[BUFF_IN_MAX] = '\0'; /* ... just to be sure. */
iReadActual = 0;
pFileIn = pFileOut = NULL;
iNumberOfOutputFiles = 0;
pszOutName[OUT_NAME_MAX] = '\0'; /* ... just to be sure. */
cLiteralChar = cAtomicChar = cChunkStartChar = cChunkEndChar = NO_CHAR;
iChunkNesting = 0;
pcOutputStart = (char*)pcBuff;
iOutputLen = 0;
if ((pFileIn = fopen("input-utf-8.txt", "r")) == NULL)
{
printf("What? Where?\n");
return 1;
}
while ((iReadActual = fread(pcBuff, sizeof(char), BUFF_IN_MAX, pFileIn)) > 0)
{
char *pcPivot, *pcStop;
pcBuff[iReadActual] = '\0'; /* ... just to be sure. */
pcPivot = (char*)pcBuff;
pcStop = (char*)pcBuff + iReadActual;
while (pcPivot < pcStop)
{
if (cLiteralChar != NO_CHAR) /* Ignore this char? */
{
/* Yes, ignore this char. */
if (cChunkStartChar != NO_CHAR)
{
/* ... just write it out: */
fprintf(pFileOut, "%c", *pcPivot);
}
pcPivot++;
cLiteralChar = NO_CHAR;
/* End of "Yes, ignore this char." */
}
else if (cAtomicChar != NO_CHAR) /* Are we inside an atomic string? */
{
/* Yup; we are inside an atomic string. */
int bBreakInnerWhile;
bBreakInnerWhile = 0;
pcOutputStart = pcPivot;
while (bBreakInnerWhile == 0)
{
if (*pcPivot == '\\') /* Treat next char as literal? */
{
cLiteralChar = '\\'; /* Yes. */
bBreakInnerWhile = 1;
}
else if (*pcPivot == cAtomicChar) /* End of atomic? */
{
cAtomicChar = NO_CHAR; /* Yes. */
bBreakInnerWhile = 1;
}
if (++pcPivot == pcStop) bBreakInnerWhile = 1;
}
if (cChunkStartChar != NO_CHAR)
{
/* The atomic string is part of a chunk. */
iOutputLen = (size_t)(pcPivot-pcOutputStart);
fprintf(pFileOut, "%.*s", iOutputLen, pcOutputStart);
}
/* End of "Yup; we are inside an atomic string." */
}
else if (cChunkStartChar == NO_CHAR) /* Are we inside a chunk? */
{
/* No, we are outside a chunk. */
int bBreakInnerWhile;
bBreakInnerWhile = 0;
while (bBreakInnerWhile == 0)
{
/* Detect start of anything interesting: */
switch (*pcPivot)
{
/* Start of atomic? */
case '"':
case '\'':
cAtomicChar = *pcPivot;
bBreakInnerWhile = 1;
break;
/* Start of chunk? */
case '{':
cChunkStartChar = *pcPivot;
cChunkEndChar = '}';
break;
case '[':
cChunkStartChar = *pcPivot;
cChunkEndChar = ']';
break;
case '(':
cChunkStartChar = *pcPivot;
cChunkEndChar = ')';
break;
case '<':
cChunkStartChar = *pcPivot;
cChunkEndChar = '>';
break;
}
if (cChunkStartChar != NO_CHAR)
{
iNumberOfOutputFiles++;
printf("Start '%c' '%c' chunk (file %04d.txt)\n", *pcPivot, cChunkEndChar, iNumberOfOutputFiles);
sprintf((char*)pszOutName, "output/%04d.txt", iNumberOfOutputFiles);
if ((pFileOut = fopen(pszOutName, "w")) == NULL)
{
printf("What? How?\n");
fclose(pFileIn);
return 2;
}
bBreakInnerWhile = 1;
}
else if (++pcPivot == pcStop)
{
bBreakInnerWhile = 1;
}
}
/* End of "No, we are outside a chunk." */
}
else
{
/* Yes, we are inside a chunk. */
int bBreakInnerWhile;
bBreakInnerWhile = 0;
pcOutputStart = pcPivot;
while (bBreakInnerWhile == 0)
{
if (*pcPivot == cChunkStartChar)
{
/* Increase level of brackets/parantheses: */
iChunkNesting++;
}
else if (*pcPivot == cChunkEndChar)
{
/* Decrease level of brackets/parantheses: */
iChunkNesting--;
if (iChunkNesting == 0)
{
/* We are now outside chunk. */
bBreakInnerWhile = 1;
}
}
else
{
/* Detect atomic start: */
switch (*pcPivot)
{
case '"':
case '\'':
cAtomicChar = *pcPivot;
bBreakInnerWhile = 1;
break;
}
}
if (++pcPivot == pcStop) bBreakInnerWhile = 1;
}
iOutputLen = (size_t)(pcPivot-pcOutputStart);
fprintf(pFileOut, "%.*s", iOutputLen, pcOutputStart);
if (iChunkNesting == 0)
{
printf("File done.\n");
cChunkStartChar = cChunkEndChar = NO_CHAR;
fclose(pFileOut);
pFileOut = NULL;
}
/* End of "Yes, we are inside a chunk." */
}
}
}
if (cChunkStartChar != NO_CHAR)
{
printf("Chunk exceeds end-of-file. Exiting gracefully.\n");
fclose(pFileOut);
pFileOut = NULL;
}
if (iNumberOfOutputFiles == 0) printf("Nothing to do...\n");
else printf("All done.\n");
fclose(pFileIn);
return 0;
}
I've solved the nice-to-haves and one of the more-far-out-nice-to-haves.
To show this the input is a little more complex than the example in the question:
junk text
"atomic junk"
some junk text followed by a start bracket { here is the actual payload
more payload
'atomic payload { with start bracket that should be ignored'
nested start bracket { - all of this line is untouchable payload too
here is more payload
"this atomic has a literal double-quote \" inside"
"yet more atomic payload; this one's got a smiley ;-) and a heart <3"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
"here's a totally unprovoked $ sign and an * asterisk"
} trailing junk
intermittent junk
<
payload that goes in second output file } mismatched end bracket should be ignored >
end junk
Resulting file output/0001.txt:
{ here is the actual payload
more payload
'atomic payload { with start bracket that should be ignored'
nested start bracket { - all of this line is untouchable payload too
here is more payload
"this atomic has a literal double-quote \" inside"
"yet more atomic payload; this one's got a smiley ;-) and a heart <3"
end of nested bracket pair } - all of this line is untouchable payload too
this is payload too
"here's a totally unprovoked $ sign and an * asterisk"
}
... and resulting file output/0002.txt:
<
payload that goes in second output file } mismatched end bracket should be ignored >
Thanks #dawg for your help :)

boost::sregex_token_iterator not matching valid regex pattern

I have the following string:
<? repeat min=1 max=2 ?>[A-Z0-9]{6},< ? endrepeat ?>100,USD,Washington
No space between < and ? in actual string
I am using the following code:
boost::regex repeatRegex("<\? repeat min=[0-9]+ max=[0-9]+ \?>(.*)<\? endrepeat \?>");
std::string theString = "<? repeat min=1 max=2 ?>[A-Z0-9]{6},<? endrepeat ?>100,USD,Washington";
boost::sregex_token_iterator itr(repeatDefinition.begin(), repeatDefinition.end(), repeatRegex);
boost::sregex_token_iterator end;
std::cout << std::endl << repeatDefinition << std::endl;
for(; itr != end; ++itr)
{
std::cout << *itr << std::endl;
}
The code never enters the for loop. I have tested the regex with the input string in rubular regex and it apparently works. Any pointers will be greatly appreciated.
First of all, I hope you are aware of the fact that you mixed repeatDefinition and theString as identifiers?
Secondly, you need to escape \ in c++ string literals:
boost::regex repeatRegex("<\\? repeat min=[0-9]+ max=[0-9]+ \\?>(.*)<\\? endrepeat \\?>");
See it Live On Coliru
Also may I draw your attention to this answer:
RegEx match open tags except XHTML self-contained tags

Resources