How to extract data from a char[] string - c++

Currently I have a GPS connected to my Arduino chip which outputs a few lines every second. I want to extract specific info from certain lines.
$ÇÐÇÇÁ,175341.458,3355.7870,Ó,01852.4251,Å,1,03,5.5,-32.8,Í,32.8,Í,,0000*57
(Take note of the characters)
If I read this line into a char[], is it possible to extract 3355.7870 and 01852.4251 from it? (Well obviously it is, but how?)
Would I need to count the commas and then after comma 2 start putting the number together and stop at comma 3 and do the same for second number or is there another way? A way to split up the array?
The other problem with this is identifying this line because of the strange characters at it's beginning - how do I check them, because their not normal and behaves strangely?
The data I want is always in form xxxx.xxxx and yyyyy.yyyy and are unique in that form, meaning I could maybe search trough all the data not caring about which line it's on and extract that data. Almost like a preg-match, but I have no idea how to do that with a char[].
Any tips or ideas?

You can tokenize (split) the string on the comma using strtok, and then parse the numbers using sscanf.
Edit: C example:
void main() {
char * input = "$ÇÐÇÇÁ,175341.458,3355.7870,Ó,01852.4251,Å,1,03,5.5,-32.8,Í,32.8,Í,,0000*57";
char * garbage = strtok(input, ",");
char * firstNumber = strtok(NULL, ",");
char * secondNumber = strtok(NULL, ",");
double firstDouble;
sscanf(firstNumber, "%lf", &firstDouble);
printf("%f\n", firstDouble);
}

If you have strange characters at the beginning of the string, then you should start parsing it from the end:
char* input = get_input_from_gps();
// lets assume you dont need any error checking
int comma_pos = input.strrchr(',');
char* token_to_the_right = input + comma_pos;
input[comma_pos] = '\0';
// next strrchr will check from the end of the part to the left of extracted token
// next token will be delimited by \0, so you can safely run sscanf on it
// to extract actual number

Related

Iterations of while loop returns strange values

I have two questions:
Assume the characters entered by the user in input are all contained in alphabet:
If my input starts with "A", the first character in my output is "A", but if I start with any other character in alphabet, the output is the original character shifted to the right by 3. If my input starts with "A", why does my output also start at "A" and not at "D"?
If my input is a string that has spaces (e.g. "Stack Overflow"), why is the first word the only component of my output? (How is the computer interpreting this?) I understand C++ considers new lines, spaces, and tabs to be whitespace, but I thought if the space was in a string, it would be treated as a character. How can I modify my code so the space and the rest of my input is included (preferably shifted) in my output?
using namespace std;
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ##$%^&*()"; //a 62 character string
string input, output;
int shift = 3, index = 0;
cin >> input;
while(index < input.length()){
if(alphabet.find(input[index]) != NULL){
output += alphabet[(alphabet.find(input[index]) + shift) % 62];
}
index++;
}
If my input starts with "A", the first character in my output is "A", but if I start with any other character in alphabet, the output is the original character shifted to the right by 3. If my input starts with "A", why does my output also start at "A" and not at "D"?
It doesn't. It skips the "A" and does not add it to the output at all!
This is because std::string::find() DOES NOT return a pointer, it returns an index. If it does not find a match, it returns std::string::npos (-1). Comparing NULL to an index treats the NULL as index 0. So, when find() does find "A", it returns 0, which you then compare as equal to NULL (0) and thus skip adding "D" to the output. All of the other input characters make find() return indexes other than 0, so they don't compare equal to NULL and so you shift all of them (including ones that cause find() to return npos, you shift all of those to index 2).
If my input is a string that has spaces (e.g. "Stack Overflow"), why is the first word the only component of my output? (How is the computer interpreting this?) I understand C++ considers new lines, spaces, and tabs to be whitespace, but I thought if the space was in a string, it would be treated as a character. How can I modify my code so the space and the rest of my input is included (preferably shifted) in my output?
operator>> reads whitespace-delimited words. It first skips leading whitespace (unless std::noskipws is used), and then it reads until it encounters whitespace. To read a string with spaces in it, use std::getline() instead.
With that said, try this instead:
using namespace std;
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ##$%^&*()"; //a 62 character string
string input, output;
const int shift = 3;
getline(cin, input);
for (string::size_type index = 0; index < input.length(); ++index) {
string::size_type found_index = alphabet.find(input[index]);
if (found_index != string::npos) {
output += alphabet[(found_index + shift) % alphabet.size()];
}
}
/*
Or, using C++11 or later:
for (char c : input) {
auto found_index = alphabet.find(c);
... (same as above) ...
}
*/
Also, how does one format variables when asking questions on StackOverflow so that they're in little code blocks within writing a question? I see that on other people's posts, but I don't know how to do it, and it makes things far more readable.
Blocks of code can be indented by 4 spaces. The toolbar on StackOverflow's editor has a button for formatting code blocks. Just select the code and press the button.
Code inline of other text can be wrapped in `` quotes.
Click on the ? button on the right side of the editor's toolbar to see the supported formatting markup.

Efficiently appending or inserting a variable number of spaces to a string

I have a simple programme that inserts or appends a number of spaces to align text.
f()
{
string word = “This word”;
const string space = “ “;
int space_num = 5; // this number can vary
for (int i = 0; i < space_num; i++)
{
word.insert(0, space);
}
cout << word;
}
Now this works, but I was wondering if there was a more efficient way to do this. Not in terms of optimizing my programme, but more as in standard practice.
I can imagine two potential methods:
1 - Is there a way to create a string of say 20 spaces, and append a portion of those spaces rather than repeatedly adding a single space.
2 – Is there a way to create string with a variable number of spaces and append that?
Yes, both take a number of copies and a character:
word.insert(0, space_num, ' ');
word.append(space_num, ' ');
For aligning text, keep in mind you can use a string stream and the <iomanip> header, such as std::setw as well.
1 - Is there a way to create a string of say 20 spaces, and append a portion of those spaces rather than repeatedly adding a single space.
Yes, try this:
string spaces(20, ' ');
string portionOfSpaces = spaces.substr(0,10); //first 10 spaces
string newString = portionOfSpaces + word;
Generally, you can use substr to get a portion of spaces and do operations with that substring.
2 – Is there a way to create string with a variable number of spaces and append that?
Yes, see string constructor:string (size_t n, char c); and string::append

How to parse string with sscanf_s()?

I have the string (45 bytes):
String1 String2000000000001234
I need get three variable from this string:
char * var1="String1";
char * var2="String2";
int var3=1234;
Here 3 part with fixed length (15 bytes). I need save all parts to variable without spaces for strings and without leading zero for integers.
Is this possible with scanf()? How I can to do that?
Not possible with sscanf. First, you need to pass a char array (and size if you use the _s variety) and not just a char pointer (i.e. it needs to have memory associated with it). Second, strings in sscanf terminate by whitespace, and you have none between String2 and 0000. Write a custom parser for this format.
According to this, your problem should be solved by the following format:
%*[^a-zA-Z]%s%*[^a-zA-Z]%[^0]s%*[^1-9]%d
Description:
%*[^a-zA-Z] - skip(do not store) until alphabetical, i.e. skip leading spaces
%s - read first string until spaces
%*[^a-zA-Z] - skip trailing spaces until the next string
%[^0]s - read string util zeros
%*[^1-9] -skip until nonzero digits
%d - finally, read the number
The easiest would probably be:
char var1_buffer[31] = "", var2_buffer[31] = "";
sscanf(string+30, "%d", &var3);
string[30] = '\0';
sscanf(string, "%s%s", var1_buffer, var2_buffer);
var1 = strdup(var1_buffer);
var2 = strdup(var2_buffer);
which requires being able to write to the input string. If that's not possible, you could replace lines 3 and 4 with:
int p1 = 0;
sscanf(string, "%30s %n%30s", var1_buffer, &p1, var2_buffer);
if (p1 > 30)
p1 = 30;
var2_buffer[30-p1] = '\0';
In either case, you should probably add checks of the return value of sscanf to make sure the input string is well-formed.

How to remove a character from the string and change data if need it?

I have possible inputs 1M 2M .. 11M and 1Y (M and Y stand for months ) and I want to output "somestring1 somestring2.... and somestring12" note M and Y are removed and the last string is changed to 12
Example: input "11M" "hello" output: hello11
input "1Y" "hello" output: hello1
char * (const char * date, const char * somestr)
{
// just need to output final string no need to change the original string
cout<< finalStr<<endl;
}
The second string is getting output as a whole itself. So no change in its output.
The second string would be output as long as M or Y are encountered. As Stack Overflow discourages providing exact source codes, so I can give you some portion of it. There is a condition to be placed which is up to you to figure out.(The second answer gives that as well)
Code would be somewhat like this.
//Code for first string. Just for output.
for (auto i = 0 ; date[i] != '\0' ; ++i)
{
// A condition comes here.
cout << date[i] ;
}
And note that this is considering you just output the string. Otherwise you can create another string and add up the two or concatenate the existing ones.
is this homework? If not, here's what i'd suggest. (i ask about homework because you may have restrictions, not because we're not here to help)
1) do a find on 'M' in your string (using find), insert a '\0' at that position if one is found (btw i'm assuming you have well formatted input)
2) do a find on 'Y'. if one is found, insert a '\0' at that position. then do an atoi() or stringstream conversion on your string to convert to number. multiply by 12.
3) concatenate your string representation of part 1 or part 2 to your somestr
4) output.
This can probably be done in < 10 lines if i could be bothered.
the a.find('M') part and its checks can be conditional operator, then the conversion/concatenation in two or three lines at most.

C++ sscanf space delimited string

Here is my practice code:
int integer_part;
char* string_part = (char*)malloc(sizeof(1000));
char* input_string = (char*)malloc(sizeof(1000)+sizeof(int));
cin>>input_string;
sscanf(input_string, "%s %d", string_part, &integer_part);
printf("scan: %s %d", string_part, integer_part);
I am using this code to take input like abc 2012 but the result will be abc 0
Sadly I didn't see where the problem is. Can anyone help me with this a little? thank you
This reads only first space delimited string:
cin>>input_string;
Use this way:
cin>> string_part >> integer_part;
Don't mix C++ and C way of reading from streams.
You can use this way to read string without space delimited:
cin.read ( input_string, sizeof(1000)+sizeof(int) - 1);
size_t read_Len = cin.gcount();
input_string[read_Len] = '\0';
I can understand you need the power of scanf to read data in a given format.
You are misusing sizeof. If you want space for 1,000 characters, you don't want the size of 1,000 itself, you want 1,000 times the size of a character. You can use 1000 * sizeof(char). Since sizeof returns characters (and thus sizeof(char) must be 1) you can just use 1000.