Let me have a string:
string tstring = "Some arbitrarily long string which has \"double quotes\" which has to be printed verbatim";
I tried use stringstreams and quoted to extract words
stringstream stream(tstring);
string tepm;
while(stream >> std::quoted(temp))
cout << temp << endl;
But the above skips the quotes in the the quoted string
Some
arbitrarily
.
.
double quotes
.
.
verbatim
I want the quoted string printed verbatim with the quotes included
Some
arbitrarily
.
.
"double quotes"
.
.
verbatim
How do i do this using the quoted function or if it is not possible is there a better way to do this (apart from of course reading character by character and doing all the work myself)
EDIT:
Here is the MCVE as requested
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
int main(){
string sspace = "Hi this is \"Real Madrid\"";
stringstream stream(sspace);
string fpart;
while(stream >> quoted(fpart)){
cout << fpart << endl;
}
return 0;
}
I don't think std::quoted is the right tool for the job here because there's no easy way to tell if the next string had quotes that were stripped before you print it (it discards your delimiter, which is '\"' by default)
I think we can safely fall back on std::string's find method.
Include a subroutine to print all words (space delimited) that aren't within quotes
Continually read until the next quote character taking advantage of find:
Full Code:
void PrintUnquoted(std::string _in)
{
std::istringstream ss(_in);
std::string temp;
while(ss >> temp)
{
std::cout << temp << '\n';
}
}
int main(){
std::string sspace = "Hi this is \"Real Madrid\" etc.";
size_t start = 0;
size_t nextQuote = 0;
while(nextQuote = sspace.find('\"', start), nextQuote != std::string::npos)
{
size_t endQuote = sspace.find('\"', nextQuote+1);
if (endQuote == std::string::npos)
{
throw std::logic_error("Unmatched quotes");
}
PrintUnquoted(sspace.substr(start, nextQuote-start));
std::cout << sspace.substr(nextQuote, endQuote-nextQuote+1) << std::endl;
start = endQuote+1;
}
if (start < sspace.size())
{
PrintUnquoted(sspace.substr(start));
}
return 0;
}
Live Demo
If you need to store the quoted characters within a variable, the line
std::cout << sspace.substr(nextQuote, endQuote-nextQuote+1) << std::endl;
Should be easily modifiable to obtain that.
When used in input, std::quoted removes unescaped quotes from the string and un-escapes escaped quotes. So a string like this:
"some \"string with\" inner quotes"
becomes this when read in:
some "string with" inner quotes
But for this to work, the string must actually be quoted and escaped in the stream. If you do this:
std::string str = "string \"with some\" quotes";
std::stringstream ss (str);
std::cout << "stream contents: " << ss.str() << std::endl;
the stream contents will actually be:
string "with some" quotes
The escaping you're doing when declaring str doesn't end up in the stream, it's there only for the parser. If you want it to be written exactly like that in the output stream you would have to write it like this instead:
std::string str = "\"string \\\"with some\\\" quotes\"";
or better yet:
std::string str = "string \"with some\" quotes";
ss << std::quoted(str);
and leave std::quoted do it's job.
Related
The bottom line is that I need to find all the comments in some Python code and cut them out, leaving only the code itself.
But I can't do it from the opposite. That is, I find the comments themselves, but I cannot find everything except them.
I tried using "?!", Made up a regular expression like "(. *) (?! #. *)". But it does not work as I expected.
Just as in the code that I attached, there is an "else" that I tried to use too, that is, write to different variables, but for some reason it doesn't even go there
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
int main()
{
std::string line;
std::string new_line;
std::string result;
std::string result_re;
std::string path;
std::smatch match;
std::regex re("(#.*)");
std::cout << "Enter the path\n";
std::cin >> path;
std::ifstream in(path);
if (in.is_open())
{
while (getline(in, line))
{
if (std::regex_search(line, match, re))
{
for (int i = 0; i < match.size(); i++)
result_re += match[i + 1];
result_re += "\n";
}
else
{
for (int i = 0; i < match.size(); i++)
result += match[i];
//result += "\n";
}
std::cout << line << std::endl;
}
}
in.close();
std::cout << result_re << std::endl;
std::cout << "End of program" << std::endl;
std::cout << result << std::endl;
system("pause");
return 0;
}
As I said above, I want to get everything except comments, and not the other way around.
I also need to do a search for multi-line comments, which are defined in """Text""".
But in this implementation, I can’t even imagine how to do it, since now it is reading line by line, and a multi-line comment in this case with the help of a regulars program is impossible for me to get
I would be grateful for your advices and help.
1. don't try parsing your input file line by line. Instead suck in the whole text and let regex to replace all the comments, this way your entire program would look like this:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <regex>
using namespace std; // for brevity
int main() {
cout << "Enter the path: ";
string filename;
getline(cin, filename);
string pprg{ istream_iterator<char>(ifstream{filename, ifstream::in} >> noskipws),
istream_iterator<char>{} };
pprg = regex_replace(pprg, regex{"#.*"}, "");
cout << pprg << endl;
}
to handle multi-line Python literals """...""", with C++ regex is quite uneasy to do (unlike in the example above): there are few mutually exclusive requirements (imho):
regex should be extended POSIX, but
POSIX regex does not support empty regex matches, however
for crafting an RE to match a negated sequence of characters a negative look-ahead assert is required, which will be an empty match :(
thus it would mean, you'd need to think and put up some programming logic to remove multi-line Python text literals
Let's say I have
string sentence{"Hello how are you."}
And I want string sentence to have "how are you" without the "Hello". How would I go about doing that.
I tried doing something like:
stringstream ss(sentence);
ss>> string junkWord;//to get rid of first word
But when I did:
cout<<sentence;//still prints out "Hello how are you"
It's pretty obvious that the stringstream doesn't change the actual string. I also tried using strtok but it doesn't work well with string.
Try the following
#include <iostream>
#include <string>
int main()
{
std::string sentence{"Hello how are you."};
std::string::size_type n = 0;
n = sentence.find_first_not_of( " \t", n );
n = sentence.find_first_of( " \t", n );
sentence.erase( 0, sentence.find_first_not_of( " \t", n ) );
std::cout << '\"' << sentence << "\"\n";
return 0;
}
The output is
"how are you."
str=str.substr(str.find_first_of(" \t")+1);
Tested:
string sentence="Hello how are you.";
cout<<"Before:"<<sentence<<endl;
sentence=sentence.substr(sentence.find_first_of(" \t")+1);
cout<<"After:"<<sentence<<endl;
Execution:
> ./a.out
Before:Hello how are you.
After:how are you.
Assumption is the line does not start with an empty space. In such a case this does not work.
find_first_of("<list of characters>").
the list of characters in our case is space and a tab. This will search for first occurance of any of the list of characters and return an iterator. After that adding +1 movers the position by one character.Then the position points to the second word of the line.
Substr(pos) will fetch the substring starting from position till the last character of the string.
You can for example take the remaining substring
string sentence{"Hello how are you."};
stringstream ss{sentence};
string junkWord;
ss >> junkWord;
cout<<sentence.substr(junkWord.length()+1); //string::substr
However, it also depends what you want to do further
There are countless ways to do this. I think I would go with this:
#include <iostream>
#include <string>
int main() {
std::string sentence{"Hello how are you."};
// First, find the index for the first space:
auto first_space = sentence.find(' ');
// The part of the string we want to keep
// starts at the index after the space:
auto second_word = first_space + 1;
// If you want to write it out directly, write the part of the string
// that starts at the second word and lasts until the end of the string:
std::cout.write(
sentence.data() + second_word, sentence.length() - second_word);
std::cout << std::endl;
// Or, if you want a string object, make a copy from the start of the
// second word. substr copies until the end of the string when you give
// it only one argument, like here:
std::string rest{sentence.substr(second_word)};
std::cout << rest << std::endl;
}
Of course, unless you have a really good reason not to, you should check that first_space != std::string::npos, which would mean the space was not found. The check is omitted in my sample code for clarity :)
You could use string::find() to locate the first space. Once you have its index, then get the sub string with string::substr() from the index after the index of the space up to the end of the string.
One liner:
std::string subStr = sentence.substr(sentence.find_first_not_of(" \t\r\n", sentence.find_first_of(" \t\r\n", sentence.find_first_not_of(" \t\r\n"))));
working example:
#include <iostream>
#include <string>
void main()
{
std::string sentence{ "Hello how are you." };
char whiteSpaces[] = " \t\r\n";
std::string subStr = sentence.substr(sentence.find_first_not_of(whiteSpaces, sentence.find_first_of(whiteSpaces, sentence.find_first_not_of(whiteSpaces))));
std::cout << subStr;
std::cin.ignore();
}
Here's how to use a stringstream to extract the junkword while ignoring any space before or after (using std::ws), then get the rest of the sentence, with robust error handling....
std::string sentence{"Hello how are you."};
std::stringstream ss{sentence};
std::string junkWord;
if (ss >> junkWord >> std::ws && std::getline(ss, sentence, '\0'))
std::cout << sentence << '\n';
else
std::cerr << "the sentence didn't contain ANY words at all\n";
See it running on ideone here....
#include <iostream> // cout
#include <string> // string
#include <sstream> // string stream
using namespace std;
int main()
{
string testString = "Hello how are you.";
istringstream iss(testString); // note istringstream NOT sstringstream
char c; // this will read the delima (space in this case)
string firstWord;
iss>>firstWord>>c; // read the first word and end after the first ' '
cout << "The first word in \"" << testString << "\" is \"" << firstWord << "\""<<endl;
cout << "The rest of the words is \"" <<testString.substr(firstWord.length()+1) << "\""<<endl;
return 0;
}
output
The first word in "Hello how are you." is "Hello"
The rest of the words is "how are you."
live testing at ideon
I've been looking thousand of questions and answers about what I'm going to ask, but I still didn't find the way to do what I'm gonna to explain.
I have a text file from which I have to extract information about several things, all of them with the following format:
"string1":"string2"
And after that, there is more information, I mean:
The text file is something like this:
LINE 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string1":"string2"XXXXXXXXXXXXXXXXXXXXXXXXXX"string3":"string4"XXXXXXXXXXXXXXXXXXXXXXXXXXXX...('\n')
LINE 2
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string5":"string6"XXXXXXXXXXXXXXXXXXXXXXXXXX"string7":"string8"XXXXXXXXXXXXXXXXXXXXXXXXXXXX...
XXX represents irrelevant information I do not need, and theEntireString (string used in the code example) stores all the information of a single line, not all the information of the text file.
I have to find first the content of string1 and store the content of string2 into another string without the quotes. The problem is that I have to stop when I reache the last quote and I don't know how exactly do this. I suppose I have to use the functions find() and substr(), but despite having tried it repeatedly, I did not succeed.
What I have done is something like this:
string extractInformation(string theEntireString)
{
string s = "\"string1\":\"";
string result = theEntireString.find(s);
return result;
}
But this way I suppose I store into the string the last quote and the rest of the string.
"find" function just give you the position of matched string to get the resulting string you need to use the "subst" function. Try This
string start,end;
start = theEntireString.substr(1,theEntireString.find(":")-2);
end = theEntireString.substr(theEntireString.find(":")+2,theEntireString.size()-1);
That will solve you problem
Assuming either the key or value contains a quotation mark. The following will output the value after the ":". You can also use it in a loop to repeatedly extract the value field if you have multiple key-value pairs in the input string, provided that you keep a record of the position of last found instance.
#include <iostream>
using namespace std;
string extractInformation(size_t p, string key, const string& theEntireString)
{
string s = "\"" + key +"\":\"";
auto p1 = theEntireString.find(s);
if (string::npos != p1)
p1 += s.size();
auto p2 = theEntireString.find_first_of('\"',p1);
if (string::npos != p2)
return theEntireString.substr(p1,p2-p1);
return "";
}
int main() {
string data = "\"key\":\"val\" \"key1\":\"val1\"";
string res = extractInformation(0,"key",data);
string res1 = extractInformation(0,"key1",data);
cout << res << "," << res1 << endl;
}
Outputs:
val,val1
Two steps:
First we have to find the position of the : and splice the string into two parts:
string first = theEntireString.substr(0, theEntireString.find(":"));
string second = theEntireString.substr(theEntireString.find(":") + 1);
Now, we have to remove the "":
string final_first(first.begin() + 1, first.end() - 1);
string final_second(second.begin() + 1, second.end() - 1);
You don't need any string operation. I hope the XXXXX doesn't contain any '"', so You can read the both strings directly from the file:
ifstream file("input.txt");
for( string s1,s2; getline( getline( file.ignore( numeric_limits< streamsize >::max(), '"' ), s1, '"' ) >> Char<':'> >> Char<'"'>, s2, '"' ); )
cout << "S1=" << s1 << " S2=" << s2 << endl;
the little help-function Char is:
template< char C >
std::istream& Char( std::istream& in )
{
char c;
if( in >> c && c != C )
in.setstate( std::ios_base::failbit );
return in;
}
#include <regex>
#include <iostream>
using namespace std;
const string text = R"(
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string1":"string2"XXXXXXXXXXXXXXXXXXXXXXXXXX"string3" :"string4" XXXXXXXXXXXXXXXXXXXXXXXXXXXX...
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string5": "string6"XXXXXXXXXXXXXXXXXXXXXXXXXX"string7" : "string8" XXXXXXXXXXXXXXXXXXXXXXXXXXXX...
)";
int main() {
const regex pattern{R"~("([^"]*)"\s*:\s*"([^"]*)")~"};
for (auto it = sregex_iterator(begin(text), end(text), pattern); it != sregex_iterator(); ++it) {
cout << it->format("First: $1, Second: $2") << endl;
}
}
Output:
First: string1, Second: string2
First: string3, Second: string4
First: string5, Second: string6
First: string7, Second: string8
Running (with clang and libc++): http://coliru.stacked-crooked.com/a/f0b5fd383bc227fc
This is how raw string literals look in an editor that understand them: http://bl.ocks.org/anonymous/raw/9442865/
I have a working function that reads lines from a text file (CSV), but I need to modify it to be able to read double quotes (I need to have these double quotes because some of my string values contain commas, so I am using double-quotes to denote the fact that the read function should ignore commas between the double-quotes). Is there a relatively simple way to modify the function below to accommodate the fact that some of the fields will be enclosed in double quotes?
A few other notes:
I could have all of the fields enclosed in double-quotes fairly easily if that helps (rather than just the ones that are strings, as is currently the case)
I could also change the delimiter fairly easily from a comma to some other character (like a pipe), but was hoping to stick with CSV if its easy to do so
Here is my current function:
void ReadLoanData(vector<ModelLoanData>& mLoan, int dealnum) {
// Variable declarations
fstream InputFile;
string CurFileName;
ostringstream s1;
string CurLineContents;
int LineCounter;
char * cstr;
vector<string> currow;
const char * delim = ",";
s1 << "ModelLoanData" << dealnum << ".csv";
CurFileName = s1.str();
InputFile.open(CurFileName, ios::in);
if (InputFile.is_open()) {
LineCounter = 1;
while (InputFile.good()) {
// Grab the line
while (getline (InputFile, CurLineContents)) {
// Create a c-style string so we can tokenize
cstr = new char [CurLineContents.length()+1];
strcpy (cstr, CurLineContents.c_str());
// Need to resolve the "blank" token issue (strtok vs. strsep)
currow = split(cstr,delim);
// Assign the values to our model loan data object
mLoan[LineCounter] = AssignLoanData(currow);
delete[] cstr;
++LineCounter;
}
}
// Close the input file
InputFile.close();
}
else
cout << "Error: File Did Not Open" << endl;
}
The following works with the given input: a,b,c,"a,b,c","a,b",d,e,f
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
std::string line;
while(std::getline(cin, line, '"')) {
std::stringstream ss(line);
while(std::getline(ss, line, ',')) {
cout << line << endl;
}
if(std::getline(cin, line, '"')) {
cout << line;
}
}
}
I have a string str ( "1 + 2 = 3" ). I want to obtain the individual numbers of the string in their decimal values( not ASCII ). I have tried atoi and c_str(). But both them require the entire string to consist of only numbers. I am writing my code in C++.
Any help would be great.
My challenge is to evaluate a prefix expression. I am reading from a file where each line contains a prefix expression. My code snippet to tokenize and and store the variables is as shown below. Each line of the file contains numbers and operators(+,-,*) which are separated by a space.
Ex - line = ( * + 2 3 4);
ifstream file;
string line;
file.open(argv[1]);
while(!file.eof())
{
getline(file,line);
if(line.length()==0)
continue;
else
{
vector<int> vec;
string delimiters = " ";
size_t current;
size_t next = -1;
do
{
current = next + 1;
next = line.find_first_of( delimiters, current );
if((line[next] <=57)&&(line[next] >=48))
vec.push_back(atoi((line.substr( current, next - current )).c_str()));
}while (next != string::npos);
cout << vec[0] << endl;
}
}
file.close();
In this case vec[0] prints 50 not 2.
You need to learn to delimit a string. Your delimiting characters would be mathematical operators (ie:
C: creating array of strings from delimited source string
http://www.gnu.org/software/libc/manual/html_node/Finding-Tokens-in-a-String.html
In the case of the second link, you would do something like:
const char delimiters[] = "+-=";
With this knowledge, you can create an array of strings, and call atoi() on each string to get the numeric equivalent. Then you can use the address (array index) of each delimiter to determine which operator is there.
For just things like addition and subtraction, this will be dead simple. If you want order of operations and multiplication, parentheses, etc, your process flow logic will be more complicated.
For a more in-depth example, please see this final link. A simple command-line calculator in C. That should make it crystal clear.
http://stevehanov.ca/blog/index.php?id=26
You will not fall into your if, since your next position will be at a delimiter.
string delimiters = " ";
...
next = line.find_first_of( delimiters, current );
if((line[next] <=57)&&(line[next] >=48))
...
Since your delimiters consist of " ", then line[next] will be a space character.
From the description of your problem, you are missing code that will save away your operators. There is no code to attempt to find the operators.
You don't have to assume ASCII for testing for a digit. You can use is_digit() for example, or you can compare against '9' and '0'.
When you print your vector element, you may be accessing the vector inappropriately, because no item may have ever been inserted into the array.
Don't use fin.eof() to control a loop. That function is only useful after a read has failed.
There are a number of ways to get ints from a std::string, I'm choosing std::stoi() from the C++11 standard in this case.
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
typedef std::vector<int> ints;
bool is_known_operator(std::string const& token)
{
static char const* tokens[] = {"*", "/", "+", "-"};
return std::find(std::begin(tokens), std::end(tokens), token) != std::end(tokens);
}
ints tokenise(std::string const& line)
{
ints vec;
std::string token;
std::istringstream iss(line);
while (iss >> token)
{
if (is_known_operator(token))
{
std::cout << "Handle operator [" << token << "]" << std::endl;
}
else
{
try
{
auto number = std::stoi(token);
vec.push_back(number);
}
catch (const std::invalid_argument&)
{
std::cerr << "Unexpected item in the bagging area ["
<< token << "]" << std::endl;
}
}
}
return vec;
}
int main(int, const char *argv[])
{
std::ifstream file(argv[1]);
std::string line;
ints vec;
while (std::getline(file, line))
{
vec = tokenise(line);
}
std::cout << "The following " << vec.size() << " numbers were read:\n";
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, "\n"));
}