This is probably a rookie question, but I couldn't find the answer in the search.
I got a variable:
char buffer[ 128 ];
now I've made it's value through a search script, coming from a big file to:
"Density # 15°C kg/m3 990.1 ( 991.0 Max ).BR.Viscocity #50°C cSt 355."
This is a specific line of 128 chars that I'm intrested in, more specifically the float "990.1". I need to get this out of all my files which is a bunch so getting the program to search for that specific text is not ok (I'll need to loop through a lot of files), it has to search for the first float. I've been trying with sscanf, but been stuck on it for a while now so I thought I'd ask.
Any help would be much appreciated!
If the float value you're looking for is always between kg/m3 and (space) you can use strstr to exctract the piece of string and then convert to float.
http://www.cplusplus.com/reference/cstring/strstr/
char *start;
char *end;
double val;
start = strstr( buffer, "kg/m3 " );
start += 6;
end = strstr( start, " " );
*end = 0;
val = atof( start );
*end = ' ';
Note that I look for the termination space and convert to null termination character.
So atof parses buffer starting from start and stops after the last digit.
Later I restore the space to leave the original string unchanged.
Thanks for the input everybody. So I went with the comments answer of πάντα ῥεῖ by using parsing, mainly because of the whitespace giving me issues on Paolo's suggestion. This is what has worked out for me:
float num;
string dummy;
istringstream iss( buffer );
while( !iss.eof() && dummy != "(")
{
iss >> num;
if(iss.fail()) {
iss.clear();
iss >> dummy;
continue;
}
}
Related
I'm attempting to write a lexer and parser but I'm having trouble getting the final variable in a text file due to in_file.tellg() equaling -1. My program only works if I add a space character after the variable, otherwise I get a compiler error. I want to mention that I'm able to get every other variable in the text file but the last one. I believe the cause of the problem is in_file.peek()!=EOF setting in_file.tellg() to -1.
My program is something like this:
ifstream in(file_name);
char c;
in >> noskipws;
while(in >> c ){
if(is_letter_part_of_variable(c)) {
int start_pos = in.tellg(),
end_pos,
length;
while(is_letter_part_of_variable(c) && in.peek()!=EOF ) {
in>>c;
}
end_pos = in.tellg(); // This becomes -1 for some reason
length = end_pos - start_pos; // Should be 7
// Reset file pointer to original position to chomp word.
in.clear();
in.seekg(start_pos-1, in.beg);
// The word 'message' should go in here.
char *identifier = new char[length];
in.read(identifier, length);
identifier[length] = '\0';
}
}
example.text
message = "Hello, World"
print message
I tried removing peek()!= EOF which gives me an eternal loop. I tried !in_file.eof() and that also makes tellg() equal to -1. What can I do to fix/enhance this code?
I believe the cause of the problem is in_file.peek()!=EOF setting in_file.tellg() to -1.
Close. peek attempts to read a character and returns EOF if it reads past the end of the stream. Reading past the end of a stream sets the stream's fail bit. tellg returns -1 if the fail bit is set.
Simple Solution
clear the fail bit before calling tellg.
Better solution
Use std::string.
std::string identifier;
while(in>>c && is_letter_part_of_variable(c)) {
identifier += c;
}
All of the messing around with peek, seekg, tellg and the dreaded new vanish.
I'm pretty new to C++. I have a text doc that looks like this:
InputFile.txt
...
.
..
.
.
....
TIME/DISTANCE = 500/ 0.1500E+05
..
..
.
...
TIME/DISTANCE = 500/ 1.5400E+02
.
...
...
.
TIME/DISTANCE = 500/ 320.0565
..
..
.
.
...
The one line shown keeps repeating throughout the file. My objective is to save all the numbers after the 500/ into an array/vector/another file/anything. I know how to read a file and get a line:
string line;
vector <string> v1;
ifstream txtfile ("InputFile.txt");
if (txtfile.is_open())
{
while (txtfile.good())
{
while( getline( txtfile, line ) )
{
// ?????
// if(line.find("500/") != string::npos)
// ?????
}
}
txtfile.close();
}
Does anybody have a solution? Or point me in the right direction?
Thanks in advance.
Edit: Both proposed solutions (Jerry's and Galik's) work perfectly. I love this community. :)
This is one of those rare cases that (IMO) it may make sense to use sscanf in C++.
std::string line;
std::vector<double> numbers;
while (std::getline(txtfile, line)) {
double d;
if (1==sscanf(line.c_str(), " TIME/DISTANCE = 500 / %lf", &d))
numbers.push_back(d);
}
This takes each line, and attempts to treat it as having the format you care about. Where that succeeded, the return value from sscanf will be 1 (the number of items converted). Where it fails, the return value will be 0 (i.e., it didn't convert anything successfully). Then we save it if (and only if) there was a successful conversion.
Also note that sscanf is "smart" enough to treat a single space in the format string as matching an arbitrary amount of white-space in the input, so we don't have to try to match the amount of white space precisely.
We could vary this somewhat. If there has to be a number before the '/', but it could be something different from 500, we could replace that part of the format string with %*d. That means sscanf will search for a number (specifically an integer) there, but not assign it to anything. If it finds something other than an integer, conversion will fail, so (for example) TIME/DISTANCE ABC/1.234 would fail, but TIME/DISTANCE 234/1.l234 would succeed.
When processing your line then you can use line.find() to check its the right line and to find your data:
if(line.find("TIME/DISTANCE") != std::string::npos)
{
// this is the correct line
}
Once you have the correct line you can get the position of the data like this:
std::string::size_type pos = line.find("500/");
if(pos != std::string::npos)
{
// pos holds the position of the numbers you want
std::string wanted_numbers = lint.substr(pos + 4); // get only the numbers in a string
}
Hope that helps
EDIT: Fixed bug (adding 4 to pos to skip over the "500/" part)
I have a project for my advanced c++ class that's supposed to do a number of things, but I'm trying to focus on this function first, because after it works I can tweak it to fulfill the other needs. This function searches through a file and performs a word count by counting the number of times ' ' appears in the document. Maybe not accurate, but it'll be a good starting place. Here's the code I have right now:
void WordCount()
{
int count_W = 0; //Varaible to store word count, will be written to label
int i, c = 0; //i for iterator
ifstream fPath("F:\Project_1_Text.txt");
FileStream input( "F:\Project_1_Text.txt", FileMode::Open, FileAccess::Read );
StreamReader fileReader( %input );
String ^ line;
//char ws = ' ';
array<Char>^ temp;
input.Seek( 0, SeekOrigin::Begin );
while ( ( line = fileReader.ReadLine() ) != nullptr )
{
Console::WriteLine( line );
c = line->Length;
//temp = line->ToCharArray();
for ( i = 0; i <= c; i++)
{
if ( line[i] == ' ' )
count_W++;
}
//line->ToString();
}
//Code to write to label
lblWordCount->Text = count_W.ToString();
}
All of this works except for one problem. When I try to run the program, and open the file, I get an error that tells me the Index is out of bounds. Now, I know what that means, but I don't get how the problem is occurring. And, if I don't know what's causing the problem, I can't fix it. I've read that it is possible to search through a string with a for loop, and of course that also holds true for a char array, and there is code in there to perform that conversion, but in both cases I get the same error. I know it is reading through the file correctly, because the final program also has to perform a character count (which is working), and it read back the size of each line in the target document perfectly from start to finish. Anyway, I'm out of ideas, so I thought I'd consult a higher power. Any ideas?
Counting whitespace is simple:
int spaces = std::count_if(s.begin(), s.end(),
[](unsigned char c){ return std::isspace(c); });
Two notes, though:
std::isspace() cannot be used immediately with char because char may be signed and std::isspace() takes an int which is required to be positive.
This counts the number of spaces, not the number of words (or words - 1): words may be separated by sequences of spaces consisting of more than one consecutive space.
It could be your loop. You're going from i=0 to i=c, but i=c is too far. You should go to i=c-1:
for ( i=0; i<c; i++)
I'm trying to convert the expression "5 + b * 18" to "5+16.89*18". My problem is inside the while loop. I managed to remove the spaces.
My code:
double number = 16.89;
size_t found;
ostringstream converted;
string str ("5 + b * 18");
str.erase(remove(str.begin(),str.end(),' '),str.end());
found = str.find_first_of (VALID_CHARS);
while (found != string::npos)
{
converted << fixed << setprecision (8) << number;
str.insert(found, converted.str());
found = str.find_first_of (VALID_CHARS,found + 1);
}
Can anyone help me?
Ty
insert() will shift the contents of the string to the right after the inserted text, but does not delete the character at the given position. You should use replace(), specifying a size of ` (to replace just a single character)
Is this homework? If not, I'd really advice against doing this kind of parsing yourself. There are dedicated libraries for this kind of things which have been extensively tested, such as muParser.
Use sprintf. It's great for converting most primitive types into strings.
int main()
{
double number = 16.89;
char buffer [50];
sprintf(buffer, "5 + %f * 18",number);
}
I'm trying to build a program to solve a problem in a text book I bought recently and it's just driving me crazy.
I have to built a sentence reverser so I get the following:
Input = "Do or do not, there is no try."
Output = "try. no is there not, do or Do"
Here's what I've got so far:
void ReverseString::reversalOperation(char str[]) {
char* buffer;
int stringReadPos, wordReadPos, writePos = 0;
// Position of the last character is length -1
stringReadPos = strlen(str) - 1;
buffer = new char[stringReadPos+1];
while (stringReadPos >= 0) {
if (str[stringReadPos] == ' ') {
wordReadPos = stringReadPos + 1;
buffer[writePos++] = str[stringReadPos--];
while (str[wordReadPos] != ' ') {
buffer[writePos] = str[wordReadPos];
writePos++;
wordReadPos++;
}
} else {
stringReadPos--;
}
}
cout << str << endl;
cout << buffer << endl;
}
I was sure I was on the right track but all I get for an output is the very first word ("try.") I've been staring at this code so long I can't make any headway. Initially I was checking in the inner while look for a '/0' character as well but it didn't seem to like that so I took it out.
Unless you're feeling masochistic, throw your existing code away, and start with std::vector and std::string (preferably an std::vector<std::string>). Add in std::copy with the vector's rbegin and rend, and you're pretty much done.
This is utter easy in C++, with help from the standard library:
std::vector< std::string > sentence;
std::istringstream input( str );
// copy each word from input to sentence
std::copy(
(std::istream_iterator< std::string >( input )), std::istream_iterator< std::string >()
, std::back_inserter( sentence )
);
// print to cout sentence in reverse order, separated by space
std::copy(
sentence.rbegin(), sentence.rend()
, (std::ostream_iterator< std::string >( std::cout, " " ))
);
In the interest of science, I tried to make your code work as is. Yeah, it's not really the C++ way to do things, but instructive nonetheless.
Of course this is only one of a million ways to get the job done. I'll leave it as an exercise for you to remove the trailing space this code leaves in the output ;)
I commented my changes with "EDIT".
char* buffer;
int stringReadPos, wordReadPos, writePos = 0;
// Position of the last character is length -1
stringReadPos = strlen(str) - 1;
buffer = new char[stringReadPos+1];
while (stringReadPos >= 0) {
if ((str[stringReadPos] == ' ')
|| (stringReadPos == 0)) // EDIT: Need to check for hitting the beginning of the string
{
wordReadPos = stringReadPos + (stringReadPos ? 1 : 0); // EDIT: In the case we hit the beginning of the string, don't skip past the space
//buffer[writePos++] = str[stringReadPos--]; // EDIT: This is just to grab the space - don't need it here
while ((str[wordReadPos] != ' ')
&& (str[wordReadPos] != '\0')) // EDIT: Need to check for hitting the end of the string
{
buffer[writePos] = str[wordReadPos];
writePos++;
wordReadPos++;
}
buffer[writePos++] = ' '; // EDIT: Add a space after words
}
stringReadPos--; // EDIT: Decrement the read pos every time
}
buffer[writePos] = '\0'; // EDIT: nul-terminate the string
cout << str << endl;
cout << buffer << endl;
I see the following errors in your code:
the last char of buffer is not set to 0 (this will cause a failure in cout<
in the inner loop you have to check for str[wordReadPos] != ' ' && str[wordReadPos] != 0 otherwise while scanning the first word it will never find the terminating space
Since you are using a char array, you can use C string library. It will be much easier if you use strtok: http://www.cplusplus.com/reference/clibrary/cstring/strtok/
It will require pointer use, but it will make your life much easier. Your delimiter will be " ".
What where the problems with your code and what are more cplusplusish ways of doing is yet well written. I would, however, like to add that the methodology
write a function/program to implement algorithm;
see if it works;
if it doesn't, look at code until you get where the problem is
is not too productive. What can help you resolve this problem here and many other problems in the future is the debugger (and poor man's debugger printf). It will make you able to see how your program actually works in steps, what happens to the data etc. In other words, you will be able to see which parts of it works as you expect and which behaves differently. If you're on *nix, don't hesitate to try gdb.
Here is a more C++ version. Though I think the simplicity is more important than style in this instance. The basic algorithm is simple enough, reverse the words then reverse the whole string.
You could write C code that was just as evident as the C++ version. I don't think it's necessarily wrong to write code that isn't ostentatiously C++ here.
void word_reverse(std::string &val) {
size_t b = 0;
for (size_t i = 0; i < val.size(); i++) {
if (val[i] == ' ') {
std::reverse(&val[b], &val[b]+(i - b));
b = ++i;
}
}
std::reverse(&val[b], &val[b]+(val.size() - b));
std::reverse(&val[0], &val[0]+val.size());
}
TEST(basic) {
std::string o = "Do or do not, there is no try.";
std::string e = "try. no is there not, do or Do";
std::string a = o;
word_reverse(a);
CHECK_EQUAL( e , a );
}
Having a multiple, leading, or trailing spaces may be degenerate cases depending on how you actually want them to behave.