I am trying to find a substring within a given string. However, the substring I am searching for can include special characters, namely '#' and '%'. Whenever '#' is encountered, the value of the character can be any digit, and '%' can be any character (any ascii character). Would it be best to iterate through the substring, search for any characters that come before a '%' or '#' in the main string, then test each character in the main string after that? I am not sure where else to begin.
I'd keep it simple. Regex is slow and adds a bunch of code.
Test the char values one at a time and exit early if not a match. Check against a match if not a wild card otherwise against a range based on the wild card. # is any char, % is any digit. Appears from your question that the wild cards are in the substring, not target string.
Here's the commented code:
#include <string>
#include <optional>
#include <iostream>
#include <array>
std::optional<size_t> match(const std::string& s_sub, const std::string& s)
{
if (s.length() < s_sub.length())
return std::nullopt;
for (size_t i = 0; i <= s.length() - s_sub.length(); i++)
for (size_t offset = 0; offset < s_sub.length(); offset++)
{
// Check for char match or wild cards "#" or "%" (any char or any digit)
if (s_sub[offset] == '#'
|| (s_sub[offset] == '%' && (s[offset + i] <= 9 || s[offset + i] >= 0))
|| s_sub[offset] == s[offset + i])
{
if (offset == s_sub.length() - 1)
return i; // if done and still matched, return position
else
continue; // Check next char if not done
}
else
break; // early exit if no match
}
return std::nullopt;
}
int main()
{
std::array<std::array<const char*, 2>, 4> args{ {{"%aa#", "5k7aaxxx"}, {"a", "ba"}, {"g%#h", "r7g4jh"}, {"a", "bcdef"} }};
for (const auto& set : args)
{
auto result = match(set[0], set[1]);
if (result)
std::cout << "Substring \"" << set[0] << "\" in \""<< set[1] << "\"" " located at " << result.value() << '\n';
else
std::cout << "Substring \"" << set[0] << "\" in \"" << set[1] << "\"" " not found" << '\n';
}
}
compiler explorer
I have made a program that takes a string into a class EncryptedString then encrypts said string removing anything that is not a space or a lower or uppercase letter. Everything seems to be working fine until I enter a string with something like 496496#####!#!!!4 then it deletes some, and keeps others. I have some examples of what is supposed to be output.
Input: Hello World!
Expected Decrypted: Hello World
Expected Encrypted: Ifmmp Xpsme
Output Decrypted: Hello World
Output Encrypted: Ifmmp Xpsme
Hello World works, just fine and deletes the !
However when I try to do "A apple ran away in autumn z!!14? I get this
Input: A apple ran away in autumn z!!14?
Expected Decrypted: A apple ran away in autumn z
Expected Encrypted: B bqqmf sbo bxbz jo bvuvno a
Output Decrypted: A apple ran away in autumn z 3
Output Encrypted: B bqqmf sbo bxbz jo bvuvno a!4
And here is one more example.
Input: Emily Dickinson1152163!!!#####!!!
Expected Decrypted: Emily Dickinson
Expected Encrypted: Fnjmz Ejeljotpo
Output Decrypted: Emily Dickinson015 ??
Output Encrypted: Fnjmz Ejdljotpo126!!##!!
I thought it may be that when I am iterating the code over decrypt.length() and enCry.length() it's going over the elements? However, I felt like it wasn't that as it's able to delete other numbers and symbols just fine but for some reason, some are staying. Is there something wrong with my code below during my iterations that can cause this?
//This function takes the phrase,word or sentence and encrypts it, removing any illegal characters aside from ' ' and then proceeds to decrypt it then output them to the get functions.
void EncryptedString::set(string str)
{
char chBase = 'A';
string enCry = str;
for (int i = 0; i < enCry.length(); i++)
{
char ch = enCry[i];
if (enCry[i] < chBase && enCry[i] != ' ')
{
enCry.erase(enCry.begin() + i);
}
else if (enCry[i] > chBase + 25 && enCry[i] < tolower(chBase) && enCry[i] != ' ')
{
enCry.erase(enCry.begin() + i);
}
else if (enCry[i] > tolower(chBase + 25) && enCry[i] != ' ')
{
enCry.erase(enCry.begin() + i);
}
else
{
if (enCry[i] == chBase + 25)
{
enCry[i] = 'A';
}
else if (enCry[i] == tolower(chBase) + 25)
{
enCry[i] = 'a';
}
else if (enCry[i] == ' ')
{
enCry[i] = ' ';
}
else
{
enCry[i] = ch + 1;
}
}
}
EncryptedString::encryption = enCry;
string decrypt = enCry;
for (int i = 0; i < decrypt.length(); i++)
{
char ch = decrypt[i];
if (decrypt[i] == 'A')
{
decrypt[i] = 'Z';
}
else if (decrypt[i] == 'a')
{
decrypt[i] = 'z';
}
else if (decrypt[i] == ' ')
{
decrypt[i] = ' ';
}
else
{
decrypt[i] = ch - 1;
}
}
decrypted = decrypt;
}
//This function outputs the decryption after the phrase was encrypted.
const string EncryptedString::get()
{
return decrypted;
}
//This function outputs the encryption of the phrase.
const string EncryptedString::getEncrypted()
{
return EncryptedString::encryption;
}
As some more information here is what is in main.cpp where I am using these functions. I thought maybe it was because I was setting it twice in test2 but I tested test1 by adding numbers to hello world and that output just kept some of the numbers with it. If you need to see that example I will provide.
#include "EncryptedString.h"
#include <windows.h>
int main()
{
cout << "TEST 1" << endl << endl;
EncryptedString test1("Hello World!");
cout << test1.get();
cout << endl << endl;
cout << test1.getEncrypted();
cout << endl << endl << "TEST 2" << endl << endl;
EncryptedString test2;
test2.set("A apple ran away in autumn z!!14?");
cout << endl << endl;
cout << test2.get();
cout << endl << endl;
cout << test2.getEncrypted();
cout << endl << endl;
test2.set("Emily Dickson1152163!!!#####!!!");
cout << test2.get() << endl << endl << test2.getEncrypted();
//being used for me to see the output.
Sleep(15000);
}
If someone can see where I went wrong or if maybe something is off with my iteration I'd be grateful. Thank anyone for reading all of this as I know it's probably a lot and thank you for any help that you can give me. Also would this be considered a logic error or structure error? I believe logic but I could be wrong and I would like to know so I don't make that mistake in the future when asking for help.
I'm having trouble printing a binary tree. Basically each node contains two values - key and data. The problem is for this assignment,
I am expected to use double-space instead of \t. Basically it means, \t = 2 spaces, \t\t = 4 spaces, \t\t\t = 6 spaces
My problem is, I have implemented the printIndented method in the following way -
void
TreeDictionary::printIndented(TreeNode * node, int level) {
if (node == NULL)
return;
if (level == 0)
{
std::cout << node->_key << ':' << node->_data << "\n";
level++;
printIndented(node->_left, level);
printIndented(node->_right, level);
}
else
{
if ((node->_left == NULL) && (node->_right == NULL))
cout << '\t';
cout << "\t" << node->_key << ':' << node->_data << endl;
if ((node->_left != NULL) && (node->_right != NULL))
cout << '\t';
printIndented(node->_left, level);
if ((node->_left != NULL) && (node->_right != NULL))
cout << '\t';
printIndented(node->_right, level);
}
}
which is giving me an output as follows -
---=WHAT I AM GETTING=---
pineapple:0
kiwi:1
grapes:3
apple:5
orange:6
lime:8
olives:9
mango:10
strawberry:4
watermelon:7
---=EXPECTED OUTPUT=--- (as you see it prints 2 spaces instead of each \t)
pineapple:0
kiwi:1
grapes:3
apple:5
NULL
NULL
NULL
orange:6
lime:8
NULL
olives:9
mango:10
NULL
NULL
NULL
NULL
strawberry:4
NULL
watermelon:7
NULL
NULL
It seems like I am unable to account for the NULL values and print NULL whenever a NULL entry is found. All help is appreciated!
NOTE : The expected output is for default indent-level that is 0 for this program.
You're not really using the information that you're getting from knowing the level that you're at. Think of it as indenting from the left most edge of the screen. Per level you want to indent it by 2*level spaces. From the output, it looks like a NULL node prints out NULL. You could try something along the lines of:
Indent(Treenode *node, int level){
std::cout << std::string(2*level, ' ');
if(node == NULL){
std::cout << "NULL" << std::endl;
}else{
std::cout << node->_key << ":" << node->_data << std::endl;
level += 1;
Indent(node->_right, level);
Indent(node->left, level);
}
}
First of all, you should also check if the first node, at level 0, has childs. Else you could run into an error if there is only one node in your tree.
Second, I encourage you to use curling braces after the if statements, this is confusing and not very readable:
if((node->_left != NULL) && (node->_right != NULL)) {
cout << "\t"; //or in your case maybe: cout << " "; //see point 3
}
Third point, when you want to print a space instead of a '\t' you should do ' ' instead of '\t'. You also use "\t", which is the syntax for printing a string instead of a character, this is not wrong but I think you need to understand the principle. '\t' = const char, "\t" = const string
4th, I don't really understand what criterium you maintain for printing with different kind of indentation, so if you can explain what you are trying to accomplish with the if statements that would be great, then I can explain it to you as well.
If you have any questions left or you find this not helpfull just tell me :)
Good luck!
I am trying to find the position at which a character was found.
const char* normalize(std::string path)
{
std::cout << "executed " << path << std::endl;
//"foo//\\\bar////bar2///../.\bar2" -- foo/bar/bar2
std::size_t found;
std::size_t found2;
std::size_t curchar = 0;
std::string final;
std::string buffer;
bool notdone = true;
while (notdone) {
//std::cout << "loop" << std::endl;
//find the current element
// can be / or \
found = path.find("/", curchar);
found2 = path.find("\\",curchar);
std::cout << found << std::endl;
SDL_Delay(2000);
if (found != std::string::npos && found2 != std::string::npos) {
if (found < found2){
//read from the curchar to the slash
if (curchar-found > 1){
buffer = path.substr(curchar,found-curchar-1);
//add to path
final = final + "/" + buffer;
}
curchar = found+1;
//buffer will be the file/component
}else{
if (curchar-found2 > 1){
buffer = path.substr(curchar,found2-curchar-1);
//add to path
final = final + "/" + buffer;
}
curchar = found2+1;
}
}else if(found != std::string::npos){
//std::cout << "loop2" << found == std::string::npos << std::endl;
//std::cout << "loop2 " << path.substr(curchar, 1) << std::endl;
if (curchar-found > 1){//
buffer = path.substr(curchar,found-curchar-1);
//add to path
final = final + "/" + buffer;
}
curchar = found+1;
}else if(found2 != std::string::npos){
std::cout << "loop3" << std::endl;
if (curchar-found2 > 1){
buffer = path.substr(curchar,found2-curchar-1);
//add to path
final = final + "/" + buffer;
}
curchar = found2+1;
}else{
std::cout << "finishing" << std::endl;
final = final + "/" + path.substr(curchar,path.size()-curchar);
notdone = false;
}
}
return final.c_str();
}
normalize("test/");
This code should print out '4', but it instead prints out 18. It prints out 18 in an infinite loop. However, if I use std::cout << path.find("/", curchar) << std::endl it does print 4. At first I thought that it wasn't actually returning std::size_t but I checked and it was.
Your following line is creating the problem
//find the current element
// can be / or \
found = path.find("/", curchar);
I ran on my linux terminal and GCC treated as next line as continuation of comment of above line.
basic.cpp:18:9: warning: multi-line comment [-Wcomment]
// can be / or \
^
basic.cpp: In function ‘const char* normalize(std::string)’:
basic.cpp:21:22: warning: ‘found’ may be used uninitialized in this function [-Wmaybe-uninitialized]
std::cout << found << std::endl;
^
Now due to above comment style, your next line(code) was treated as comment. As found was not initialized so it had garbage value which screwed up your logic as it did not go inside the path where you have reset the flag notdone.
However GCC or any other compiler should give warning(usage of uninitialize variable) and if we would have carefully read, we might have back-trace and understood the problem.
Solution for this would be to change the comment style as
/* // can be / or \ */
Here's the contents of a text file:
SQUARE 2
SQUARE
RECTANGLE 4 5
I'm trying to figure out why my strtok() loop won't take the end of the 2ND "SQUARE" and just make the length = 0. Don't fully understand the concept behind strtok either, I wouldn't mind a lecture about strtok. Here's the code:
#include <cstring>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
#include<iomanip>
using std::setprecision;
#include <fstream>
using std::ifstream;
const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 20;
const char* const DELIMITER = " ";
int main()
{
// create a file-reading object
ifstream fin;
fin.open("geo.txt"); // open a file
if (!fin.good())
return 1; // exit if file not found
//PI
float pi = 3.14159265359;
//DIMENSIONS
float length, width, height, radius;
//AREAS, PERIMETERS, VOLUMES
float areaSquare, periSquare;
float areaRectangle, periRectangle;
float areaCube, volCube;
float areaPrism, volPrism;
float areaCircle, periCircle;
float areaCylinder, volCylinder;
// read each line of the file
while (!fin.eof())
{
// read an entire line into memory
char buf[MAX_CHARS_PER_LINE];
fin.getline(buf, MAX_CHARS_PER_LINE);
// parse the line into blank-delimited tokens
int n = 0; // a for-loop index
// array to store memory addresses of the tokens in buf
const char* token[MAX_TOKENS_PER_LINE] = {0}; // initialize to 0
// parse the line
token[0] = strtok(buf, DELIMITER); // first token
if (token[0]) // zero if line is blank
{
for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
{
token[n] = strtok(0, DELIMITER); // subsequent tokens
if (!token[n] || token[n]==0) break;
}
}
if(strcmp("SQUARE", token[0]) == 0) //1
{
length = atof(token[1])?atof(token[1]):0;
areaSquare = length * length;
periSquare = 4 * length;
cout.setf(ios::fixed|ios::showpoint);
cout << setprecision(2);
cout << token[0] << ' ' << "length="<< token[1] << ' ';
cout << "Area=" << areaSquare << ' ';
cout << "Perimeter=" << periSquare << '\n';
cout.unsetf(ios::fixed|ios::showpoint);
cout << setprecision(6);
}
else if(strcmp("RECTANGLE", token[0]) == 0) //2
{
length = atof(token[1])?atof(token[1]):0;
width = atof(token[2])?atof(token[2]):0;
areaRectangle = length * width;
periRectangle = 2 * length + 2 * width;
cout.setf(ios::fixed|ios::showpoint);
cout << setprecision(2);
cout << token[0] << ' ' << "length="<< token[1] << ' ';
cout << "width=" << token[2] << ' ' ;
cout << "Area=" << areaRectangle << ' ';
cout << "Perimeter=" << periRectangle << '\n';
cout.unsetf(ios::fixed|ios::showpoint);
cout << setprecision(6);
}
else
{
cout << "End of program. Press ENTER to exit.";
cin.ignore(1000,10);
break;
}
}
}
Your segmentation fault is caused by this:
length = atof(token[1])?atof(token[1]):0;
You made the mistake of assuming that token[1] was tokenized. If you look at your 2nd 'SQUARE' you'll find that for that line it will have set token[1] to NULL. You then pass NULL to atof() which understandably errors out.
You're also using strtok() improperly. There is no reason to strcpy() from its result, because strtok() itself is a destructive operation.
So here's a lecture about strtok.
Firstly, it's evil, but so handy that you use it anyway sometimes. Tokenizers can be a pain in the butt to write.
The idea behind strtok was to create an easy tokenizer. A tokenizer is a pain in the butt to write, and the interface for it is actually fairly decent if you don't mind making it really easy to blow your computer up with it. You can use a very small amount of code to parse command line arguments, for example.
However, strtok is destructive to the string you use it on. It will replace the token that it finds with a 0, automatically null-terminating the returned value. That means that you can directly use the returned string without needing to copy it. A string like this:
here are spaces0
Is changed into
here0are0spaces0
where 0 delimits end of string character (0). This is done in place, and you get pointers to here, are, and spaces.
strtok uses static variables - meaning it retains state information between calls. On the first call you pass it a pointer to the string you're trying to tokenize; from then on, you pass it a NULL pointer to signal that you want it to continue where it left off before. It returns the next token, returning NULL when it finds the end of the string.
An strtok loop is very easy to write. This code will tokenize a string for you properly. The following example code is ugly, but I blame being tired.
char *input_string; // Just so we have it
const int MAX_TOKENS = 10; // Arbitrary number
char *tokens[MAX_TOKENS]; // This will do all the storage we need.
tokens[0] = strtok(input_string, " -=\""); // Setup call.
int number_of_tokens = 1; // We've already filled tokens[0], so we have 1 token. We want to start filling from 1.
do {
if (tokens[number_of_tokens] = strtok(NULL," -=\"")) number_of_tokens++;
else break;
} while(number_of_tokens < MAX_TOKENS);
That first line in the loop is common practice for C programmers, but is ugly for readability. Here's what it does:
a) It sets tokens[number_of_tokens] to the return value of strtok.
b) If that is NULL, it terminates the loop (second line).
addendnum: there is an inline test. You can do if (a = 1) and it will return true and set a to 1. You can do if (a = 0) it will return false while setting a to 0. This line takes advantage of that fact, if strtok() returns NULL, well, that's false.
c) If that is not NULL, tokens[number_of_tokens] now contains a pointer to the next token found in the string.
d) Since a token was found, the number of tokens (number_of_tokens) is incremented.
5) It reuses the variable that keeps count of how many tokens there are as an index into the array of pointers that it keeps.
6) It loops infinitely until it either meets the condition of strtok returning NULL, or the while() condition (in this case, there are more than 10 tokens).
If it was given this string:
here are some=words0
It would be
*tokens[0]="here"
*tokens[1]="are"
*tokens[2]="some"
*tokens[3]="words"
*tokens[4] = NULL
number_of_tokens = 4
As you can see, there's no need to copy anything, because that string is replaced in memory as such:
here0are0some0words0
where 0 delimits end of string character (0).
I hope this answers your questions.
Here is a version that works.
Main differences are,
Have changed the array of char * to array of 20 char strings. This guarantees the array elements have memory allocated, in your case they are null pointers and stay this way when strtok returns NULL, you cannot then use a NULL pointer.
The second call to strtok is "strtok(0, DELIMITER)"
but should be "strtok(NULL, DELIMITER)".
I think they are the only diffs, but use the diff utility to check.
#include <cstring>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
#include<iomanip>
using std::setprecision;
#include <fstream>
using std::ifstream;
const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 20;
const char* const DELIMITER = " ";
int main()
{
// create a file-reading object
char *tok;
ifstream fin;
fin.open("geo.txt"); // open a file
if (!fin.good())
return 1; // exit if file not found
//PI
float pi = 3.14159265359;
//DIMENSIONS
float length, width, height, radius;
//AREAS, PERIMETERS, VOLUMES
float areaSquare, periSquare;
float areaRectangle, periRectangle;
float areaCube, volCube;
float areaPrism, volPrism;
float areaCircle, periCircle;
float areaCylinder, volCylinder;
// read each line of the file
while (!fin.eof())
{
// read an entire line into memory
char buf[MAX_CHARS_PER_LINE];
fin.getline(buf, MAX_CHARS_PER_LINE);
// parse the line into blank-delimited tokens
int n = 0; // a for-loop index
// array to store memory addresses of the tokens in buf
// const char* token[MAX_TOKENS_PER_LINE] = {0}; // initialize to 0
char token[MAX_TOKENS_PER_LINE][20];
for (n=0;n<MAX_TOKENS_PER_LINE;n++)
{
token[n][0] = NULL;
}
// parse the line
tok = strtok(buf, DELIMITER); // first token
if (tok == NULL)
break;
strcpy(token[0],tok);
if (token[0]) // zero if line is blank
{
for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
{
tok = strtok(NULL, DELIMITER); // subsequent tokens
if (tok == NULL)
break;
strcpy(token[n],tok);
// if (!token[n] || token[n]==0) break;
}
}
if(strcmp("SQUARE", token[0]) == 0) //1
{
length = atof(token[1])?atof(token[1]):0;
areaSquare = length * length;
periSquare = 4 * length;
cout.setf(ios::fixed|ios::showpoint);
cout << setprecision(2);
cout << token[0] << ' ' << "length="<< token[1] << ' ';
cout << "Area=" << areaSquare << ' ';
cout << "Perimeter=" << periSquare << '\n';
cout.unsetf(ios::fixed|ios::showpoint);
cout << setprecision(6);
}
else if(strcmp("RECTANGLE", token[0]) == 0) //2
{
length = atof(token[1])?atof(token[1]):0;
width = atof(token[2])?atof(token[2]):0;
areaRectangle = length * width;
periRectangle = 2 * length + 2 * width;
cout.setf(ios::fixed|ios::showpoint);
cout << setprecision(2);
cout << token[0] << ' ' << "length="<< token[1] << ' ';
cout << "width=" << token[2] << ' ' ;
cout << "Area=" << areaRectangle << ' ';
cout << "Perimeter=" << periRectangle << '\n';
cout.unsetf(ios::fixed|ios::showpoint);
cout << setprecision(6);
}
else
{
cout << "End of program. Press ENTER to exit.";
cin.ignore(1000,10);
break;
}
}
}
Ok. When your line
const char* token[MAX_TOKENS_PER_LINE] = {0};
creates an array of pointers, but none of them point to anything. The first element is set to 0 (which is a NULL address) and the rest are not initialised. When you run and process line 2 (which has 1 element) token[0] points to 'SQUARE' but token[1] is given the value 0x00 (NULL). This is an invalid memory location. You then process token[1] with the line
length = atof(token[1])?atof(token[1]):0;
and this causes a Segmentation fault because token[1] is a NULL pointer. In my version token[1] is a valid pointer to a NULL string, which sets length to 0. I suggest you compile with the -g flag (eg g++ -g test.cpp -o test). Then call 'gdb test' and use break, run, continue commands to step through the code. You can use the print command to display the contents of variables.
In the first run in gdb just enter 'run'. This will fail, then enter 'bt' which will tell you the failing line, let's call it linenumber.
In the second run enter 'break linenumber' and then 'run' and the execution will stop on the failing line but before it is executed. You can then look at the contents of the variables which will give you a big clue to why it is failing.
Here is some working C++ based closely on your code.
I've revised the I/O handling; fin.getline() reports whether it got a line or not, so it should be used to control the loop; fin.eof() is a red flag warning in my estimation (as is feof(fp) in C).
The core dump occurs because you don't check that you got a length token after the word SQUARE. The revised code checks that it got exactly the correct number of tokens, complaining if not. The code using strtok() has been unified into a single loop; it contains a diagnostic print statement that shows the token just found (valuable for checking what's going on).
I removed a pile of unused variables; each variable is defined and initialized in the calculation blocks.
There are endless possible reservations about using C strings and strtok() in C++ (the printing would be a lot more succinct if all the code were written in C using the C standard I/O functions like printf()). You can find a discussion of the alternatives to strtok() at Strange strtok() error. You can find another discussion on why strtok() is a disaster in a library function at Reading user input and checking the string.
Working code for the 3 lines of data in the question
#include <cstring>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
using std::cerr;
#include<iomanip>
using std::setprecision;
#include <fstream>
using std::ifstream;
const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 20;
const char* const DELIMITER = " ";
int main()
{
// create a file-reading object
const char *fname = "geo.txt";
ifstream fin;
fin.open(fname); // open a file
if (!fin.good())
{
cerr << "Failed to open file " << fname << endl;;
return 1; // exit if file not found
}
// read each line of the file
char buf[MAX_CHARS_PER_LINE];
while (fin.getline(buf, sizeof(buf)))
{
int n = 0;
const char *token[MAX_TOKENS_PER_LINE] = {0};
char *position = buf;
while ((token[n] = strtok(position, DELIMITER)) != 0)
{
cout << "Token " << n << ": " << token[n] << endl;
n++;
position = 0;
}
if (strcmp("SQUARE", token[0]) == 0 && n == 2)
{
float length = atof(token[1])?atof(token[1]):0;
float areaSquare = length * length;
float periSquare = 4 * length;
cout.setf(ios::fixed|ios::showpoint);
cout << setprecision(2);
cout << token[0] << ' ' << "length="<< token[1] << ' ';
cout << "Area=" << areaSquare << ' ';
cout << "Perimeter=" << periSquare << '\n';
cout.unsetf(ios::fixed|ios::showpoint);
cout << setprecision(6);
}
else if (strcmp("RECTANGLE", token[0]) == 0 && n == 3)
{
float length = atof(token[1])?atof(token[1]):0;
float width = atof(token[2])?atof(token[2]):0;
float areaRectangle = length * width;
float periRectangle = 2 * length + 2 * width;
cout.setf(ios::fixed|ios::showpoint);
cout << setprecision(2);
cout << token[0] << ' ' << "length="<< token[1] << ' ';
cout << "width=" << token[2] << ' ' ;
cout << "Area=" << areaRectangle << ' ';
cout << "Perimeter=" << periRectangle << '\n';
cout.unsetf(ios::fixed|ios::showpoint);
cout << setprecision(6);
}
else
{
cout << "Unrecognized data: " << buf << endl;
}
}
}