This question already has answers here:
Encode/Decode URLs in C++ [closed]
(19 answers)
Closed 8 years ago.
I am writing a program, that has a small, self-written HTTP Server inside. Now i get Data via POST over the socket. My problem is, how do I unescape the String the best way in C++? I get Data like:
command=foo%26bar
but i want it to be
command=foo&bar
Whats the best way to achieve this in C++?
EDIT: If someone is interested in my solution, here it is:
void HttpServer::UnescapePostData(std::string & data) {
size_t pos;
while ((pos = data.find("+")) != std::string::npos) {
data.replace(pos, 1, " ");
}
while ((pos = data.find("%")) != std::string::npos) {
if (pos <= data.length() - 3) {
char replace[2] = {(char)(std::stoi("0x" + data.substr(pos+1,2), NULL, 16)), '\0'};
data.replace(pos, 3, replace);
}
}
}
Well, there is no formal definition of the right terminology, but this kind of process is generally describing as "unescaping", or "parsing" rather than escaping. You would like to parse the application/x-www-form-urlencoded-encoded string.
And the answer is rather boring: you just do it. That's all. application/x/www-form-urlencoded only does two things: replace spaces with "+" signs, and replace most other kind of punctuation (including the real "+" sign itself) with %xx, where xx is the octet in hexadecimal.
So, you just roll up your sleeves, and do it. Scan the string, replace the + character with a space, and replace each occurence of %xx with the single character, the evaluated hexadecimal octet. There's nothing particularly mysterious about the process. It is exactly what it appears to be.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I have the following code that I'm trying to decipher from a former colleague:
void getIP(int p){
char tstr[80];
char *pt;
strcpy(ipBuf,"NA");
if(p==-1)return;
strcpy(tstr, panes[p].stream.c_str());
pt=strchr(tstr,':');
if(pt){
*pt='x'; //Blank first one
pt=strchr(tstr,':');
if(pt){
*pt='\0';
strcpy(ipBuf,&tstr[7]);
}
}
}
I'm relatively inexperienced with C++ so was hoping I could get some help with how this code works. Its purpose I think is to take a camera stream address and strip the port number and any extra stuff off to just give an IP address. I cannot understand through how it achieves this other than it seems to use ":" as a delimiter at a couple of stages?
To explain the function a little more, int p is a position on the grid, then it takes the stream address from that grid square and puts it into tstr.
But any explanation beyond that is much appreciated.
I [...] was hoping I could get some help with how this code works.
strcpy(tstr, panes[p].stream.c_str());
Copy the contents of the std::string designated by panes[p].stream into array tstr, yielding an independent copy as a C string.
pt=strchr(tstr,':');
if(pt){
*pt='x'; //Blank first one
Locate the first appearance of a ':' character in the local copy of the string. If the character is found, then replace it with an 'x'.
pt=strchr(tstr,':');
if(pt){
*pt='\0';
Locate the (new) first appearance of a ':' character in the local copy of the string. If it exists, replace it with a '\0', which will be recognized as a string terminator. That is, truncate the string at that point.
strcpy(ipBuf,&tstr[7]);
Copy the contents of the local C string, starting at the eighth character (because arrays are indexed from 0, not from 1), into the space to which ipBuf points. The magic number 7 is suspicious here, but I don't have enough information to be able to determine whether it is erroneous. My guess would be that the code is assuming that the original first colon will always appear at index 6, with the result that the substring between the (original) first and second colons is copied, but there are cleaner, clearer, more efficient ways to do that.
Improved version, with more C++
... and better names, and no unnecessary copying, and explanatory comments:
void getIP(int pane_index){
if (pane_index >= 0) {
// for clarity and convenience
std::string &url_string = panes[pane_index].stream;
// hardcoded per the original code
const size_t ip_offset = 7;
// Locate the first colon, if any, after the start of the ip address
size_t colon_index = url_string.find(':', ip_offset);
if (colon_index != std::string::npos) {
// Extract the name / IP address as the substring starting at
// offset 7 and stopping just before the second colon
size_t ip_len = colon_index - ip_offset;
strncpy(ipBuf, url_string.c_str() + ip_offset, ip_len);
ipBuf[ip_len] = '\0';
return;
} // else there are no colons after the start of the ip address
} // else an invalid pane index was given
// no machine name / IP address is available
strcpy(ipBuf, "NA");
}
As already noted in the previous comment, the function searches for the second occurence of ':' in tstr string and if it is found, replaces it with null character, effectively cutting off any remaining characters from the string. Than the characters in the string from index [7] to the null character (previously ':') are copied to ipBuf. For example, let say url is rtsp://192.168.0.200:551/stream.sdp. Digit 1 in "192" has index [7] in the string. So copying from that position to the second ":" (or null char) would copy "192.168.0.200".
What is technically wrong in this program? The expected result is 6 since that is the total number of words present in the string.
#include <iostream>
using namespace std;
int main()
{
string str = " Let's count the number of words ";
int word = 0;
for (int i = 0; str[i] != '\0';)
{
if ((str[i] == 32 && str[i + 1] == 32) || (str[i] == 32 && str[i - 1] == 32))
{
++i;
}
else if ((str[i] == 32 && str[i - 1] != 32) || (str[i] == 32 && str[i + 1] != 32))
{
word++;
}
++i;
}
cout << "No. of words: " << word << endl;
return 0;
}
My incorrect result:
No. of words: 0
Also, if I try changing the spaces in the string or even the string itself to a totally new set of spaced out words, say:
string str = " Hello world ";
string str = "Hello world! How are you? ";
I still get incorrect results, but different from 0. I'm new to C++ programming and these kinds of strange behaviors are giving me nightmares. Is this common? What I can do to get this corrected?
If you could highlight or correct my program the way I'd written it, it would be much helpful and quick for me to understand the mistake instead of having to know some new commands at this point. Because, as I said, I'm a total beginner in C/C++.
Thanks for your time!
I'm new to C++ programming and these kinds of strange behaviors are giving me nightmares. Is this common?
Yes, it's very common. You've written a load of logic piled up in a heap and you don't have the tools to understand how it behaves.
What I can do to get this corrected?
You can work on this from both directions:
debug this to improve your understanding of how it operates:
identify in advance what you expect it to do for some short input, at each line
single-step through it in the debugger to see what it actually does
think about why it doesn't do what you expected
Sometimes the problem is that your code doesn't implement your algorithm correctly, and sometimes the algorithm itself is broken, and often it's a bit of both. Working through both will give you some insight.
write code that is easier to understand in the first place (and equivalently, write algorithms that are easy to reason about).
This depends on you having some intuition about whether something is easy to reason about, which you develop from iterating step 1.
... instead of having to know some new commands at this point.
Well, you need to learn to use a debugger anyway, so now is as good a time to start as any.
We can certainly improve the existing code, although I'd prefer to fix the logic. In general I'd encourage you to abstract your existing if conditions out into little functions, but the problem is that they don't currently seem to make any sense.
So, how do we define a word?
Your code says it is at least one non-space character preceded or followed by a space. (Do definitely prefer ' ' to 32, by the way, and std::isspace is better than either.)
However your code's implied definition is problematic, because:
each word longer than one character has both a first and last character, and you'll count each of them
you can't check whether the first character is preceded by anything, without going out of bounds
the last character is followed by the null terminator, but you don't count that as whitespace
Let's just choose a different definition, that doesn't require reading str[i-1], and doesn't require the tricky traversal your current code gets wrong.
I claim that a word is a contiguous substring of non-whitespace characters, and words are separated by contiguous substrings of whitespace characters. So, instead of looking at each pair of consecutive characters, we can write pseudocode to work in those terms:
for (current = str.begin(); current != str.end(); ) {
// skip any leading whitespace
current = find_next_non_whitespace(str, current);
if (current != str.end()) {
// we found a word
++words;
current = find_next_whitespace(str, current);
}
}
NB. When I talked about abstracting your code out into little functions, I meant things like find_next_non_whitespace - they should be trivial to implement, easy to test, and have a name that tells you something.
When I said your existing conditions didn't seem to make sense, it's because replacing
if ((str[i] == 32 && str[i + 1] == 32) || (str[i] == 32 && str[i - 1] == 32))
with, say,
if (two_consecutive_spaces(str, i))
prompts more questions than it answers. Why have a special case for exactly two consecutive spaces? Is it different to just one space? What will actually happen if we have two words with a single space between them? Why do we advance by two characters in this case, but only one on the word branch?
The fact that the code can't easily be mapped back onto explicable logic is a bad sign - even if it worked (which we know it doesn't), we don't understand it well enough to ever change, extend or refactor it.
I think you have some ways to do it. Take a look at this code. Very similar to yours:
string s = " Let's count the number of words ";
int word = 0;
for (auto i = 0; s[i] != '\0'; i++) {
if (i == 0) {
if (s[i] != ' ') {
++word;
}
continue;
}
if (s[i - 1] == ' ' && s[i] != ' ') {
++word;
}
}
cout << "No of Words: " << word << endl;
The idea is to iterate over the string reading character by character. So we do some logic:
If we are in the first string character and it's equals to ' ', go to the next loop iteration
If we are in the first string character and it's different from ' ', means we are starting a word, so counts it and jump to the next loop iteration.
If we reach the second if, means we are not at the first position, so trying to access i - 1 should be valid. Then we just check if the previous char is a blank space and the current one it's not. This means we are starting a new word. So counts it and jump to the next loop iteration.
Another and more simple way to do it is using stringstream:
string s = " Let's count the number of words ";
stringstream ss(s);
string sub;
int word = 0;
while (ss >> sub) {
++word;
}
cout << "No of Words: " << word << endl;
This way you're basically extracting word by word from your string.
This question already has answers here:
How to strip all non alphanumeric characters from a string in c++?
(12 answers)
Closed 6 years ago.
I'm trying to remove all non alphabet characters from an inputed string in c++ and don't know how to. I know it probably involves ascii numbers because that's what we're learning about. I can't figure out how to remove them. We only learned up to loops and haven't started arrays yet. Not sure what to do.
If the string is Hello 1234 World&*
It would print HelloWorld
If you use std::string and STL, you can:
string s("Hello 1234 World&*");
s.erase(remove_if(s.begin(), s.end(), [](char c) { return !isalpha(c); } ), s.end());
http://ideone.com/OIsJmb
Note: If you want to be able to handle strings holding text in just about any language except English, or where programs use a locale other than the default, you can use isalpha(std::locale).
PS: If you use a c-style string such as char *, you can convert it to std::string by its constructor, and convert back by its member function c_str().
If you're working with C-style strings (e.g. char* str = "foobar") then you can't "remove" characters from a string trivially (as a string is just a sequence of characters stored sequentially in memory - removing a character means copying bytes forward to fill the empty space used by the deleted character.
You'd have to allocate space for a new string and copy characters into it as-needed. The problem is, you have to allocate memory before you fill it, so you'd over-allocate memory unless you do an initial pass to get a count of the number of characters remaining in the string.
Like so:
void BlatentlyObviousHomeworkExercise() {
char* str = "someString";
size_t strLength = ... // how `strLength` is set depends on how `str` gets its value, if it's a literal then using the `sizeof` operator is fine, otherwise use `strlen` (assuming it's a null-terminated string).
size_t finalLength = 0;
for(size_t i = 0; i < strLength; i++ ) {
char c = str[i]; // get the ith element of the `str` array.
if( IsAlphabetical(c) ) finalLength++;
}
char* filteredString = new char[ finalLength + 1 ]; // note I use `new[]` instead of `malloc` as this is C++, not C. Use the right idioms :) The +1 is for the null-terminator.
size_t filteredStringI = 0;
for(size_t i = 0; i < strLength; i++ ) {
char c = str[i];
if( IsAlphabetical(c) ) filteredString[ filteredStringI++ ] = c;
}
filteredString[ filteredStringI ] = '\0'; // set the null terminator
}
bool IsAlphabet(char c) { // `IsAlphabet` rather than `IsNonAlphabet` to avoid negatives in function names/behaviors for simplicity
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
I do not want to spoil the solution so I will not type out the code, only describe the solution. For your problem think of iterating through your string. Start with that. Then you need to decide if the currently selected character is part of the alphabet or not. You can do this numerous different ways. Checking ASCII values? Comparing against a string of the alphabet? Once you decide if it is a letter, then you need to rebuild the new string with that letter plus the valid letters before and after that you found or will find. Finally you need to display your new string.
If you look at an ascii table, you can see that A-Z is between 65-90 and a-z is between 97-122.
So, assuming that you only need to remove those characters (not accentuated), and not other characters from other languages for example, not represented in ascii, all you would need to do is loop the string, verify if each char is in these values and remove it.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Given a character array in a URL format like
char *s="www.google.com\tsp finite.aspx"
While decoding it space should be replaced by %20 and thus the string becomes:
char *s="www.google.com\tsp%20finite.aspx"
We are not allowed to use a new character array but allowed to use some character variables for temporary use. Should not use any containers also. The array contains enough space to contain the decoded data so no need to worry about the more space to be taken.
I followed the Brute-Force mechanism where all the characters from the point of finding a space to the end of the array are to be swapped. But this is not the most efficient way to solve the problem.
Can any body tell me which is the best way (algorithm) to decrease the no. of swappings in order to acquire the solution.
I am assuming the string has been allocated using malloc
First calculate the number of spaces and the length of the string
Then the new length = old length + number of spaces * 2. Use realloc to expand the string.
The work backwards from the end and copy to the new length. When encountering space copy in %20 instead.
The main problem could be that swapping space with %20 will require moving the whole string 2 characters more .
Here's an idea :
Parse the whole string once, and count the number of spaces in the string
The new length of the array would be strlen(original) + 2*(nOfSpaces) (let's call it from now on NewLen)
Parse the whole string once again but starting backwards.
You will copy the previous string contents inside itself but at an offset until you hit a space
you will have a pointer starting at strlen(original) and one starting at NewLen
parse from strlen(original) backwards until you find a space (the substrLen will be subLen)
memcpy from [strlen(original)-curParsingindex] to [NewLen - curParsingIndex-2*(enteredSpaces)] sublen amount
Instead of copying the space, put %20 instead
This way you will avoid moving the string forward each time you hit a space.
Regarding step 4 , you might think about using a temporary variable for the sublen, since you might end up writing in the same memory zone by mistake (take an example where all the spaces are at the beginning).
This is a classic interview coding question; a good solution for this starts with a good interface for your solution. Something that works is:
char* replaceChar(char* in, char c)
char *in - string you want to decode
c - the char you want to replace with it's hexa value ASCII code ( HEX val ascii for ' ' is 0x20)
Pseudocode:
allocate a buffer the same size as the input buffer
get the index of the first occurrence of the char you want to replace (strcspn can help with that)
copy the content of the of the input up to the found index to the new buffer.
reallocate the new buffer size to newSize=oldSize+2
add % to the new string
repeat until you reach the end of the string.
return a pointer to the new string
You can also do it in place on the original string but that solution is a bit more complicated because you have to shift everything.
You can do it in two passes. The key idea is to first count the number of spaces and then move each character directly to its final position. In your approach you shift the remainder of the string at each occurrence of a space.
#include <stdio.h>
int main ()
{
char str[1000] = "www.example.com/hello world !";
int length;
int spaces;
int i;
char *ptr;
printf ("\"%s\"\n", str);
// pass 1:
// calculate length and count spaces
length = 0;
spaces = 0;
for (ptr = str; *ptr; ptr++) {
if (*ptr == ' ') {
spaces++;
}
length++;
}
// pass 2:
// transform string
// preserve terminating null character
ptr = str + length + 2 * spaces;
for (i = length; i >= 0; i--) {
char c = str[i];
if (c == ' ') {
*ptr-- = '0';
*ptr-- = '2';
*ptr-- = '%';
}
else {
*ptr-- = c;
}
}
printf ("\"%s\"\n", str);
return 0;
}
This question already has answers here:
Remove spaces from std::string in C++
(19 answers)
Closed 9 years ago.
I am trying to do something that I imagine is quite straightforward but I am new to C/C++ so it is proving a little bit tricky.
Essentially I am trying to remove a single whitespace from data contained within a .txt. Each piece of data is on a separate line:
01011 0
11100 1
00001 0
and so on. I have been able to count the number of lines, and the size of each string (including the whitespace) however I want to lose the whitespace located within the data.
My code for reading the data in (including whitespace is as follows):
std::ifstream myfile ("random.txt");
std::string str;
if(myfile.is_open())
{
while (std::getline(myfile, str))
{
i++;
Size = str.size();
data_input[i] = str;
line_num = i;
array_count = line_num * Size;
}
i = 0;
}
I have looked at various other posts but can't seem to find one that fits what I am trying to achieve. Any help would be appreciated.
str.erase(str.find(' '), 1);
Explanation:
The call to str.find returns the position (index) of the space.
The call to str.erase removes one character, starting at that position.