I am following along with Stanford's CS106B course by myself. One of the assignments is asking for a recursive algorithm which will pull all brackets and braces out of a string that is provided to a function. I have attached below my code. I have managed to get the function to pull out all the brackets and braces. I have not managed to get it to return anything. It runs endlessly. I am wondering how to get it to stop without using a single loop or global variable. I've been trying this all day, seen many people's solutions for similar assignments, read the textbook, and have listened to the lectures many times yet I cannot get it to return anything.
Also: str.insert inserts a string into the position requested.
isalpha finds if the character in question is an alphabet in a string.
isdigit finds if the character in question is a digit in a string.
These are all functions provided in the Stanford libraries but I do not believe they are native to C++.
/*
* TODO: remove and replace this file header comment
* You will edit and turn in this file.
* Remove starter comments and add your own
* comments on each function and on complex code sections.
*/
#include <iostream> // for cout, endl
#include <string> // for string class
#include "recursion.h"
#include "testing/SimpleTest.h"
using namespace std;
//string strTemp;
/*
* TODO: Replace this comment with a descriptive function
* header comment.
*/
string operatorsFrom(string str) {
string strTemp;//Not working because this is defined everytime
/* TODO: Implement this function. */
// str.insert(str.length(),"strTemp");
if(!isalpha(str[0])&&!isdigit(str[0])){
strTemp = str[0];
str.insert(str.length(),strTemp);
operatorsFrom(str.erase(0,1));
}
if(isalpha(str[0])||isdigit(str[0])){
operatorsFrom(str.erase(0,1));
}
return str;
}
/*
* TODO: Replace this comment with a descriptive function
* header comment.
*/
bool operatorsAreMatched(string ops) {
/* TODO: Implement this function. */
return false;
}
/*
* The isBalanced function assumes correct implementation of
* the above two functions operatorsFrom and operatorsMatch.
* It uses operatorsFrom to extract the operator characters
* from the input string and then confirms that those
* operators are balanced by using operatorsMatch.
* You should not modify the provided code in the isBalanced
* function. If the previous two functions have been implemented
* correctly, the provided isBalanced will correctly report whether
* the input string has balanced bracketing operators.
*/
bool isBalanced(string str) {
string ops = operatorsFrom(str);
return operatorsAreMatched(ops);
}
/* * * * * * Test Cases * * * * * */
PROVIDED_TEST("operatorsFrom on simple example") {
EXPECT_EQUAL(operatorsFrom("vec[3]"), "[]");
}
PROVIDED_TEST("operatorsAreMatched on simple example") {
EXPECT(operatorsAreMatched("{}"));
}
PROVIDED_TEST("isBalanced on example from writeup") {
string example ="int main() { int x = 2 * (vec[2] + 3); x = (1 + random()); }";
EXPECT(isBalanced(example));
}
PROVIDED_TEST("isBalanced on non-balanced examples from writeup") {
EXPECT(!isBalanced("( ( [ a ] )"));
EXPECT(!isBalanced("3 ) ("));
EXPECT(!isBalanced("{ ( x } y )"));
}
I have tried to get this function to return the parentheses, brackets, etc. It does manage to pull those out of text very well, but it gets stuck in the first if loop and does not return anything. So far I have tried to figure out some sort of counter, but that seems impossible without either a global variable or a loop of some sort, which are not allowed.
Edit: I have added the entire program. The function that is the issue is the string operatorsFrom function.
Related
The problem asks to create a program that asks the user to enter some text and that text will be surrounded by asterisks depending on the width of the screen for example if the user inputs "Hello world" the output should be:
****************
* Hello World! *
****************
I've tried to create the functions but I'm stuck becaus of a compiler error with the shown minimal code.
Question: Why does it tell me no matching function for within_width(text, 80)?
Some of the code I have is below:
#include <iostream>
#include <string>
void display_header (std::string &header) {
std::string text;
header = text;
}
bool within_width (std::string& text, unsigned short int& max_width) {
}
int main() {
std::string text;
std::cout << "Please enter header text: ";
std::getline(std::cin, text);
if (within_width(text, 80)) {
// call the display_header function and pass in the text
// inputted by the user
} else {
std::cout << text;
}
return 0;
}
This declaration of the function
bool within_width (std::string& text, unsigned short int& max_width)
asks for an unsigned short int variable, because it has a reference parameter, see the second &.
To satisfy it, you need to put the value 80 into a variable and give the variable as parameter.
unsigned short int MyWidth=80;
if (within_width(text, MyWidth))
Alternatively (but I assume you are not allowed) you can use a call by value parameter
bool within_width (std::string& text, unsigned short int max_width)
Then you could call as shown.
I won't give a full answer to the exercise here, just some clues.
the display_header() and within_width() functions need to know the string given in parameters but may not modify it ; thus the type of this parameter should be const std::string & (the const was missing).
the second parameter of the within_width() function is just an integer that will be compared to the length of the string ; you don't need to pass it by reference (or at least const), rather by value. Here, the (non-const) reference prevents from passing the literal constant 80.
(it seems to be the main concern of the question after edition)
You need to reason step by step.
all of this depends on the size of the string (12 for Hello World!) ; this information is available via size(text) (or text.size())
(https://en.cppreference.com/w/cpp/iterator/size)
(https://en.cppreference.com/w/cpp/string/basic_string/size)
This size will have to be compared to max_width
Displaying the line with header will require 4 more characters because * will be prepended and * will be appended.
Thus the two surrounding lines will have the length size(header)+4 too.
In order to create such a string made of *, you could use a constructor of std::string taking two parameters : the count of characters and the character to be repeated.
(https://en.cppreference.com/w/cpp/string/basic_string/basic_string)
Send all of this to std::cout in the correct order.
Edit: Just noticing that this answer probably goes far beyond the scope of the task you have been given (just filling in some skeleton that has been provided by your teacher).
I'll still leave it here to illustrate what could be done with arbitrary input. Maybe you want to experiment a little further than what you have been asked...
bool within_width(...)
Pretty simple: string.length() <= max – just wait a second, you need to consider asterisks and spaces at beginning and end of output, so: max - 4
But you can do better, you can split the string, best at word boundaries. That's a bit difficult more difficult, though:
std::vector<std::string> lines;
// we'll be starting with an initially empty line:
auto lineBegin = text.begin();
auto lineEnd = text.begin();
for(auto i = text.begin(); i != text.end(); ++)
// stop condition empty: we'll stop from inside the loop...
{
// ok, we need to find next whitespace...
// we might try using text.find_first_of("..."), but then we
// need to know any whitespace characters ourselves, so I personally
// would rather iterate manually and use isspace function to determine;
// advantage: we can do other checks at the same time, too
auto distance = std::distance(lineBegin, i);
if(std::distance(lineBegin, i) > maxLineLength)
{
if(lineEnd == lineBegin)
{
// OK, now we have a problem: the word itself is too long
// decide yourself, do you want to cut the word somewhere in the
// middle (you even might implement syllable division...)
// or just refuse to print (i. e. throw an exception you catch
// elsewhere) - decide yourself...
}
else
{
lines.emplace_back(lineBegin, lineEnd);
lineBegin = lineEnd; // start next line...
}
}
// OK, now handle current character appropriately
// note: no else: we need to handle the character in ANY case,
// if we terminated the previous line or not
if(std::isspace(static_cast<unsigned char>(*i)))
{
lineEnd = i;
}
// otherwise, we're inside a word and just go on
}
// last line hasn't been added!
lines.emplace_back(lineBegin, lineEnd);
Now you can calculate maximum length over all the strings contained. Best: Do this right when adding a new line to the vector, then you don't need a separate loop...
You might have noticed that I didn't remove whitespace at the end of the strings, so you wouldn't need to add you own one, apart, possibly, from the very last string (so you might add a lines.back() += ' ';).
The ugly part, so far, is that I left multiple subsequent whitespace. Best is removing before splitting into lines, but be aware that you need to leave at least one. So:
auto end = text.begin();
bool isInWord = false; // will remove leading whitespace, if there is
for(auto c : text)
{
if(std::isspace(static_cast<unsigned char>(c)))
{
if(isInWord)
{
*end++ = ' '; // add a single space
isInWord = false;
}
}
else
{
*end++ = c;
isInWord = true;
}
}
This would have moved all words towards the beginning of the string, but we yet to drop the surplus part of the string yet contained:
text.erase(end, text.end());
Fine, the rest is pretty simple:
iterate over maximum length, printing a single asterisk in every loop
iterate over all of your strings in the vector: std::cout << "* " << line << "*\n";
repeat the initial loop to print second line of asterisks
Finally: You introduced a fix line limit of 80 characters. If console is larger, you just won't be using the entire available width, which yet might be acceptable, if it is smaller, you will get lines broken at the wrong places.
You now could (but that's optional) try to detect the width of the console – which has been asked before, so I won't go any deeper into.
Final note: The code presented above is untested, so no guarantee to be bugfree!
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 years ago.
Improve this question
I have a C file with multiple inline comments that begin with //.
For example,
u32 Status;
// Read foo peripherals status
Status = foo_periph_status(foo_Instance);
// Check if foo is ready to turn right
if ((Status) & (FOO_STATUS_TURN_RIGHT_MASK)) {
// Get FOO current state
foo_Instance->CurrentState = Foo_GetCurrentState(incoming_data);
// Get FOO format
foo_Instance->CurrentState.metadata.Format = Foo_GetFormat(incoming_data)
In above code I'll like to change all the // inline comments from their current format to a /* Inline comments */ format.
I've tried to used,
s/\([^.*]\)\(\/\/\)\(.*\)\($\)/\1\/\*\3 \*\//
and this works for me now.
I'm wondering if there is a better way of doing this?
EDIT :
See this old answer that is much better than mine (also written in C): https://stackoverflow.com/a/12000755/6872717.
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
// Read line from file
fgets(buff, BUFSIZ, fp_r);
// Find "//" comment
p = strstr(buff, "//");
if (!p)
continue;
// If comment is at the very end of the buffer, and wouldn't fit, remove it.
if ((p - &buff[0] + strlen("/**/\n") + 1) > ARRAY_SSIZE(buff)) {
sprintf(p, "\n");
continue;
}
// Remove "*/" that would break the new comment format
do {
q = strstr(p, "*/");
if (q)
memmove(q, q + strlen("*/"), strlen(q + strlen("*/")) + 1);
} while (q);
// Write the new comment begining
sprintf(p, "/*");
// Find end of line
p = strrchr(buff, '\n');
// Check that the closing "*/" fits in the buffer
while ((p - &buff[0] + strlen("*/\n") + 1) > ARRAY_SSIZE(buff))
p--;
// Write closing "*/"
sprintf(p, "*/\n");
// Write line to file
fputs(buff, fp_w);
This will fix a line. You only need to add the code to iterate over the whole file. You need to have two files open: the one you're reading from (fp_r), and a new one (fp_w). You'll have to delete the old file, and after deleting the first one rename the new one with the same name, so that the result is an overwritten file.
This will remove any appearances of */ after the //.
Problems:
It will not handle cases where a comment is written in the "/**/" format and inside of it contains // because it is unlikely, and complicated to solve (see following examples). If this happens, the result may be an invalid comment.
Examples:
a = 7; /* // this will mess everything */
a = /*7*/b; /* // hello, this too */ c=a; // another comment
That's in single lines, and it's already complicated. Just imagine to handle it in multiline comments...
If a // is found within a string literal, the same as above happens. It has a similar difficulty, and it is also unlikely, so I won't bother solving that; it is up to you if you need it :). The result will be invalid code, too
(Thanks to #EdMorton for spotting this one).
It will truncate a line if a comment is so long that it ends near the end of the buffer. However, the resulting comment will be valid.
Proposal for these problems:
Prompt the user if a /* or */ or " is detected within a line that will be modified before actually writing it into the file, show him both the original and the modification (you would need to keep a copy of the original one), and let him decide if he prefers the old line or the new one. And let the user modify manually those lines after this has done most of the job ;-)
The problem with multiline comments (or multiline string literals, bot those are unicorns) would still exist, but maybe you could find another pattern in those, like for example a * at the very beginning of the line. Anyway, the code wouldn't be invalid; just some unwanted changes inside comments would happen.
Another solution might be to prompt the user at every change.
I'm doing a project that reads some string reactions from file at formula e.g: (5A+3B=c+10D) as an input. I need to do a parsing for the string reaction so that I can extract &(split) integer values beside a char and put them into a vector i.e vector associated with the reaction here is :[5 3 1 10].
I thought about std::strtok function but I think it cannot seperate integer values!!!
Can any one help me ??
Here my try:
int main()
{
std::string input;
std::getline(std::cin, input);
std::stringstream stream(input);
while(1) {
int n;
stream >> n;
char * pch;
pch = strtok (input," ");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.");
}
return 0;
}
}
To do some serious parsing work, you need to learn some language theory. Fortunately, it isn't very difficult.
The method we are going to cover here is what we called Top Down Recursive Parsing.
The full listing of the source code here is going to be too long for the purpose of this forum, instead, I will present some pseudo-code for it.
The first thing you will need to do is to define your grammar. What is considered valid and what is not, you represent a grammar like this:
formula := term
:= term + formula
:= term - formula
term := variable
:= coefficient variable
So a formula C + 2D can be represented as
formula
term
variable
C
+
formula
term
coefficient
2
variable
D
With this in mind, we first solve a simpler problem, there are only a few types of things we need from the input string
+
-
coefficient
variable
Only these four things are valid input, you may want to skip space. Splitting the input string into these 4 types of things is called lexical analysis. We typically implement a so called scanner to do this.
A scanner typically look like this
class Scanner
{
public:
Scanner(const char* text);
Token GetToken(); // The current token
void Scan(); // read the next token
}
Next, you will want to group these token into a tree like what I have shown you above. This logic we typically call it parsing and it implemented as a parser. You can implement a parser in many ways, here is one way you can do it with a top down predictive parser
class Parser
{
public:
private:
bool ParseVariable()
{
if (s.GetToken() is variable) { s.Scan(); return true; }
}
bool ParseTerm()
{
if (s.GetToken() is variable) { s.Scan(); return true; }
if (s.GetToken() is coefficient) { s.Scan(); return this->ParseVariable(); }
}
Scanner s;
}
The similar code goes on. Obviously one can extend the return type of those Parse() method to return something useful to its caller and assemble the representation you need for your purpose.
For my personal purposes, I wrote a few parsers for different languages. You can take a look at them as sample.
This is a sample in Python.
https://github.com/cshung/MiscLab/blob/master/GreatestCommonDivisor/polynomial_module.py
This is a sample in C++ with a small twist, I parsed the string backwards to avoid 'left recursion'
https://github.com/cshung/Competition/blob/master/Competition/LEET_BASIC_CALCULATOR.cpp
To see a top down parser in action in real life product, see this example in ChakraCore, which I proudly worked on some time ago.
https://github.com/Microsoft/ChakraCore/blob/master/lib/Parser/Parse.cpp
Edit: Sorry, it should be c++. how to use strtok in string?
FQ_ID_line[0]="1,26665;TUK.006.8955.FQ;TUK;400 BB 2 FQ;400 BB 2;899;FQ;Z_SCCFG1;Z_BSCFG1;333";
FQ_ID_line[1]="2,26223;TUK.002.8955.FQ;TUK;400 BB 2 FQ;400 BB 2;;FQ;Z_SCCFG1;Z_BSCFG1;333";
for(int FQ_i=0;FQ_i<FQ_Number;FQ_i++)
{
printf( "FQ_ID_line[FQ_i]=%u\n", FQ_ID_line[FQ_i] );
char * FQ_array=strdup(FQ_ID_line[FQ_i].c_str());
char *chars_array=strtok(FQ_array,seps);
chars_array=strtok(NULL,seps);
strcpy(DataLine[FQ_i].analog_comp_id,chars_array);
chars_array=strtok(NULL,seps);
strcpy(DataLine[FQ_i].RTU_abbr,chars_array);
chars_array=strtok(NULL,seps);
chars_array=strtok(NULL,seps);
chars_array=strtok(NULL,seps);
chars_array=strtok(NULL,seps);
chars_array=strtok(NULL,seps);
strcpy(DataLine[FQ_i].analog_scc_fep_group,chars_array);
chars_array=strtok(NULL,seps);
strcpy(DataLine[FQ_i].analog_bsc_fep_group,chars_array);
chars_array=strtok(NULL,seps);
strcpy(DataLine[FQ_i].RTU_number,chars_array);
DataLine[FQ_i].float_RTU_number=atof(chars_array);
free(FQ_array);
}
the ouput is :
DataLine[0].analog_comp_id=TUK.006.8955.FQ
DataLine[0].RTU_abbr=TUK
DataLine[0].analog_scc_fep_group=Z_SCCFG1
DataLine[0].analog_bsc_fep_group=Z_BSCFG1
DataLine[0].float_RTU_number=333
DataLine[1].analog_comp_id=TUK.002.8955.FQ
DataLine[1].RTU_abbr=TUK
DataLine[1].analog_scc_fep_group=Z_BSCFG1
DataLine[1].analog_bsc_fep_group=333
DataLine[1].float_RTU_number=
I want to the ouput:
DataLine[0].analog_comp_id=TUK.006.8955.FQ
DataLine[0].RTU_abbr=TUK
DataLine[0].analog_scc_fep_group=Z_SCCFG1
DataLine[0].analog_bsc_fep_group=Z_BSCFG1
DataLine[0].float_RTU_number=333
DataLine[1].analog_comp_id=TUK.002.8955.FQ
DataLine[1].RTU_abbr=TUK
DataLine[1].analog_scc_fep_group=Z_SCCFG1
DataLine[1].analog_bsc_fep_group=Z_BSCFG1
DataLine[1].float_RTU_number=333
The cause of the problem:
The function strtok() has many problems, due to the fact that subsequent calls depend on previous calls, and this dependency is managed in an unsafe manner:
it's not thread safe (see Robert's comment, and C++ standard section 21.8 pt 14)
if one function you call would use strtok() without you knowing, your next call to strtok() would return a lot of surprises.
Now your problem comes from the input string part: ...400 BB 2;;FQ;..., and the definition of strtok() : In subsequent calls, the function (...) uses the position right after the end of last token as the new starting location for scanning. To determine the beginning and the end of a token, the function first scans from the starting location for the first character not contained in delimiters (which becomes the beginning of the token)
So everything works well until it returns "400 BB 2". The next ";" will according to this algorithm be skipped and your code will jump over the empty field (;;) as if it didn't exist. Not ony do you have a shift in the following fields, but your last call to strtok() may even cause segmentation fault.
Solution:
Best avoid strtok(). If you like c-style, you may consider instead the use of strpbrk() with some adaptation in your code. For example:
char* get_field(char*p, char*& next, const char* s) // by ref as it's c++
{
if ((next = strpbrk(p, s)) != NULL)
*next++ = '\0';
return p;
}
with the following usage to replace strtok():
char* next;
char *chars_array = get_field(FQ_array, next, seps);
...
chars_array = get_field(next, next, seps); // instead of strtok(NULL, seps)
...
My personal recommendation, with C++, would be to consider regex expressions provided in the standard (or in boost), which would also allow for consistency check on you input data.
The full code would then look like:
regex fmt("([0-9]*,[0-9]*);(.*);(.*);(.*);(.*);(.*);(.*);(.*);(.*);([0-9]*\.*[0-9]*)");
for (int FQ_i = 0; ...)
{
smatch sm;
printf("FQ_ID_line[FQ_i]=%u\n", FQ_ID_line[FQ_i]); // ok, a cout would be better
if (regex_match(FQ_ID_line[FQ_i], sm, fmt)) {
DataLine[FQ_i].analog_comp_id = sm[2];
DataLine[FQ_i].RTU_abbr = sm[3];
DataLine[FQ_i].analog_scc_fep_group = sm[8];
DataLine[FQ_i].analog_bsc_fep_group = sm[9];
DataLine[FQ_i].RTU_number = sm[10];
DataLine[FQ_i].float_RTU_number = stof(sm[10]);
}
else
cout << " ** Non matching line ignored !!\n";
}
By fine tuning the regex, you could then check even more for consistency before assigning (Here I just did the minimum for the sake of the example).
I have a c++ project to count the LLOC of an input file, which is a file generated by a code generator consists of sequence of functions denoted F1( ), F2( ),..., Fn( ), followed by the main program and control structures like if, while, do, switch, and etc. we should count the number of: main program + functions + semicolons + equations + if statements + switch statements + while statements + for statements. I can easily count, for example, the number of ; using find function, but how can I count the number of functions? is there any way to count the substring F*( , which means every substring that starts with F and ends with ( ?
Here is my code to count the number of semicolons:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main(int argc, char ** argv) {
ifstream testfile;
std::string stringline;
std::string str2(";");
size_t found;
int positioncount = 0;
char arry[100];
testfile.open("program.cpp");
while (!testfile.eof()) {
testfile.getline(arry, 50);
stringline = arry;
if (stringline.find(str2) != std::string::npos) {
positioncount++;
}
}
cout << "\n" << positioncount;
testfile.close();
return 0;
}
Since the code is machine generated you can probably make assumptions about it which make life much easier: for example no comments, no strings containing stuff that looks like code, no nested classes, etc.
That may let you get away with basic regular expressions plus counting braces. Modern C++ has built-in regular expressions, you may want to look into that for things like your function names.
Counting occurences is commonly done with maps (cf. http://www.cplusplus.com/reference/map/map/?kw=map).