Starting from a QByteArray, I'd like to search "\n" char inside my QByteArray and join all the characters from the beginning up to "\n" and save them in a QString; after that, I'd pass to the following bytes up to the next "\n" and save these into a new QString
QByteArray MyArray= (all data from my previous process);
quint16 ByteArrayCount = MyArray.count(); // number of bytes composing MyArray
quint16 mycounter;
QString myString;
while (mycounter < ByteArrayCount)
{
if(MyArray[mycounter] != "\n")
myString.append(MyArray[mycounter]);
mycounter++;
}
This to append all bytes preceeding a new line; my problem is how to evaluate MyArray[counter], since I'm not able to check every byte when the counter increases.
Solution?
You could save yourself the trouble and simply:
QString s(myArray);
QStringList resultStrings = s.split('\n');
This will give you a list of strings split for every new line character, which is what you sound like you want to do.
Also, not to belabor the point, but you don't initialize your counter, and you really should ;)
Here is simple example of using function hello
QString str = "ooops\nhello mama\n daddy cool";
QByteArray bta;
bta.append(str);
for(quint16 index = bta.indexOf('\n');
index != -1;
index = bta.indexOf('\n', index+1)) {
/**
* Do something with index
**/
}
But according to your question there is not so clear when you say that you "not able to check every byte". If you know diapasons of available mem, you can use raw data with:
const char * ptr = MyArray.constData();
and use custom validators:
while(ptr){
if(valid(ptr) && ptr == '\n') {
/**
* do something ...
**/
}
ptr++;
}
ow and also in C/C++:
"\n" != 'n'
because "\n" - is const C string(char[2]) containing \n and EOF('\0')
and '\n' - is just simple C char;
Related
In my app I read a string field from a file in local (not Unicode) charset.
The field is a 10 bytes, the remainder is filled with zeros if the string < 10 bytes.
char str ="STRING\0\0\0\0"; // that was read from file
QByteArray fieldArr(str,10); // fieldArr now is STRING\000\000\000\000
fieldArr = fieldArr.trimmed() // from some reason array still containts zeros
QTextCodec *textCodec = QTextCodec::codecForLocale();
QString field = textCodec->ToUnicode(fieldArr).trimmed(); // also not removes zeros
So my question - how can I remove trailing zeros from a string?
P.S. I see zeros in "Local and Expressions" window while debuging
I'm going to assume that str is supposed to be char const * instead of char.
Just don't go over QByteArray -- QTextCodec can handle a C string, and it ends with the first null byte:
QString field = textCodec->toUnicode(str).trimmed();
Addendum: Since the string might not be zero-terminated, adding storage for a null byte to the end seems to be impossible, and making a copy to prepare for making a copy seems wasteful, I suggest calculating the length ourselves and using the toUnicode overload that accepts a char pointer and a length.
std::find is good for this, since it returns the ending iterator of the given range if an element is not found in it. This makes special-case handling unnecessary:
QString field = textCodec->toUnicode(str, std::find(str, str + 10, '\0') - str).trimmed();
Does this work for you?
#include <QDebug>
#include <QByteArray>
int main()
{
char str[] = "STRING\0\0\0\0";
auto ba = QByteArray::fromRawData(str, 10);
qDebug() << ba.trimmed(); // does not work
qDebug() << ba.simplified(); // does not work
auto index = ba.indexOf('\0');
if (index != -1)
ba.truncate(index);
qDebug() << ba;
return 0;
}
Using fromRawData() saves an extra copy. Make sure that the str
stays around until you delete the ba.
indexOf() is safe even if you have filled the whole str since
QByteArray knows you only have 10 bytes you can safely access. It
won't touch 11th or later. No buffer overrun.
Once you removed extra \0, it's trivial to convert to a QString.
You can truncate the string after the first \0:
char * str = "STRING\0\0\0\0"; // Assuming that was read from file
QString field(str); // field == "STRING\0\0\0\0"
field.truncate(field.indexOf(QChar::Null)); // field == "STRING" (without '\0' at the end)
I would do it like this:
char* str = "STRING\0\0\0\0";
QByteArray fieldArr;
for(quint32 i = 0; i < 10; i++)
{
if(str[i] != '\0')
{
fieldArr.append(str[i]);
}
}
QString can be constructed from a char array pointer using fromLocal8Bit. The codec is chosen the same way you do manually in your code.
You need to set the length manually to 10 since you say you have no guarantee that an terminating null byte is present.
Then you can use remove() to get rid of all null bytes. Caution: STRI\0\0\0\0NG will also result in STRING but you said that this does not happen.
char *str = "STRING\0\0\0\0"; // that was read from file
QString field = QString::fromLocal8Bit(str, 10);
field.remove(QChar::Null);
I need to be able to parse the following two strings in my program:
cat myfile || sort
more myfile || grep DeKalb
The string is being saved in char buffer[1024]. What I need to end up with is a pointer to a char array for the left side, and a pointer to a char array for the right side so that I can use these to call the following for each side:
int execvp(const char *file, char *const argv[]);
Anyone have any ideas as to how I can get the right arguments for the execvp command if the two strings above are saved in a character buffer char buffer[1024]; ?
I need char *left to hold the first word of the left side, then char *const leftArgv[] to hold both words on the left side. Then I need the same thing for the right. I have been messing around with strtok for like two hours now and I am hitting a wall. Anyone have any ideas?
I recommend you to learn more about regular expressions. And in order to solve your problem painlessly, you could utilize the Boost.Regex library which provides a powerful regular expression engine. The solution would be just several lines of code, but I encourage you to do it yourself - that would be a good exercise. If you still have problems, come back with some results and clearly state where you were stuck.
You could use std::getline(stream, stringToReadInto, delimeter).
I personally use my own function, which has some addition features baked into it, that looks like this:
StringList Seperate(const std::string &str, char divider, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
{
return Seperate(str, CV_IS(divider), seperationFlags, whitespaceFunc);
}
StringList Seperate(const std::string &str, CharValidatorFunc isDividerFunc, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
{
bool keepEmptySegments = (seperationFlags & String::KeepEmptySegments);
bool keepWhitespacePadding = (seperationFlags & String::KeepWhitespacePadding);
StringList stringList;
size_t startOfSegment = 0;
for(size_t pos = 0; pos < str.size(); pos++)
{
if(isDividerFunc(str[pos]))
{
//Grab the past segment.
std::string segment = str.substr(startOfSegment, (pos - startOfSegment));
if(!keepWhitespacePadding)
{
segment = String::RemovePadding(segment);
}
if(keepEmptySegments || !segment.empty())
{
stringList.push_back(segment);
}
//If we aren't keeping empty segments, speedily check for multiple seperators in a row.
if(!keepEmptySegments)
{
//Keep looping until we don't find a divider.
do
{
//Increment and mark this as the (potential) beginning of a new segment.
startOfSegment = ++pos;
//Check if we've reached the end of the string.
if(pos >= str.size())
{
break;
}
}
while(isDividerFunc(str[pos]));
}
else
{
//Mark the beginning of a new segment.
startOfSegment = (pos + 1);
}
}
}
//The final segment.
std::string lastSegment = str.substr(startOfSegment, (str.size() - startOfSegment));
if(keepEmptySegments || !lastSegment.empty())
{
stringList.push_back(lastSegment);
}
return stringList;
}
Where 'StringList' is a typedef of std::vector, and CharValidatorFunc is a function pointer (actually, std::function to allow functor and lambda support) for a function taking one char, and returning a bool. it can be used like so:
StringList results = String::Seperate(" Meow meow , Green, \t\t\nblue\n \n, Kitties!", ',' /* delimeter */, DefaultFlags, is_whitespace);
And would return the results:
{"Meow meow", "Green", "blue", "Kitties!"}
Preserving the internal whitespace of 'Meow meow', but removing the spaces and tabs and newlines surrounding the variables, and splitting upon commas.
(CV_IS is a functor object for matching a specific char or a specific collection of chars taken as a string-literal. I also have CV_AND and CV_OR for combining char validator functions)
For a string literal, I'd just toss it into a std::string() and then pass it to the function, unless extreme performance is required. Breaking on delimeters is fairly easy to roll your own - the above function is just customized to my projects' typical usage and requirements, but feel free to modify it and claim it for yourself.
In case this gives anyone else grief, this is how I solved the problem:
//variables for the input and arguments
char *command[2];
char *ptr;
char *LeftArg[3];
char *RightArg[3];
char buf[1024]; //input buffer
//parse left and right of the ||
number = 0;
command[0] = strtok(buf, "||");
//split left and right
while((ptr=strtok(NULL, "||")) != NULL)
{
number++;
command[number]=ptr;
}
//parse the spaces out of the left side
number = 0;
LeftArg[0] = strtok(command[0], " ");
//split the arguments
while((ptr=strtok(NULL, " ")) != NULL)
{
number++;
LeftArg[number]=ptr;
}
//put null at the end of the array
number++;
LeftArg[number] = NULL;
//parse the spaces out of the right side
number = 0;
RightArg[0] = strtok(command[1], " ");
//split the arguments
while((ptr=strtok(NULL, " ")) != NULL)
{
number++;
RightArg[number]=ptr;
}
//put null at the end of the array
number++;
RightArg[number] = NULL;
Now you can use LeftArg and RightArg in the command, after you get the piping right
execvp(LeftArg[0], LeftArg);//execute left side of the command
Then pipe to the right side of the command and do
execvp(RightArg[0], RightArg);//execute right side of command
My program use some variables of type QByteArray to contain data (bytes). That bytes maybe are special characters like '\0', 1, ... So I cannot see all elements after special character when debugging. If I use std::vector, I can see all elements. I must use QByteArray but I cannot see all element of this variable when debugging. Help me, plz!
Thanks!
Example: QByteArray bytes(4, '\0');
Now, if debug, I just see "". But I want to see "'\0', '\0', '\0', '\0'" or something like like this.
I also have the same problem with QDateTime. But I resolved by this help: http://www.qtcentre.org/threads/32336-View-QDate-and-QDateTime-in-VisualStudio-debugger
This link may help but this not resolve my problem: http://qt-project.org/wiki/IDE-debug-helpers
Example:
QByteArray ba("Hello"); //debuging, see: ba = "Hello"
ba.append('\0');
ba.append("a message"); //we just see: ba = "Hello"
I contribute here a piece of code I had to write since I could not find any method doing something close to that: display a QByteArray as a meaningful QString in a way python would do it: ascii is kept as this, special char are displayed as hexadecimal code.
If someone knows a better way ! (here it's QT 4.6)
QString toDebug(const QByteArray & line) {
QString s;
uchar c;
for ( int i=0 ; i < line.size() ; i++ ){
c = line[i];
if ( c >= 0x20 and c <= 126 ) {
s.append(c);
} else {
s.append(QString("<%1>").arg(c, 2, 16, QChar('0')));
}
}
return s;
}
Such as:
QByteArray a;
a.append("et");
a.append('\0');
a.append("voilĂ ");
qDebug() << toDebug(QByteArray(a));
returns:
"et<00>voil<e0>"
For debugging, you can convert QBytearray to QString and see the output.
For example:
QByteArray bArray;
QString str = "";
str.append(bArray);
QDebug() << str ; // this will display the content in your console/application output window
hope this will resolve your issue.
I have this:
char* original = "html content";
And want to insert a new
char* mycontent = "newhtmlinsert";
into the "original" above just before </body> tag in the "original".
My new orginal is now:
char* neworiginal = "html content before </body>" + "newhtmlinsert" + "html content after </body>";
Basically i want to take a char* orginal and convert it into a char* neworiginal which has the original content plus new content that i added before the </body> in the "original html content"
here is the modified code, i still need some help:
* original data */
data = _msg_ptr->buff();
data_len = _msg_ptr->dataLen();
/*location of </body> in the original */
char *insert = strstr(data, "</body>");
/*length of the new buffer string */
int length = strlen(data)+strlen(ad_content);
newdata =(char*)malloc(sizeof(char)*length);
memset(newdata, 0, length);
/*copy the original data upto </body> into newdata*/
memcpy(newdata,data,insert-data);
/*now add the ad_content */
strcat(newdata,ad_content);
/*copy the data from </body> to end of original string(data) into newdata */
memcpy(newdata,data,data_len - ending );
how do i implement the the last statement : memcpy(newdata,data,data_len - ending );
i need to copy the remainder of the data from my char* data beginning from an
the very end...how do i correctly compute the "ending" parameter in the memcpy?
here is the c++ version using strings
char *insert = strstr(_in_mem_msg_ptr->buff(), "</body>");//get pointer to </body>
string ad_data = string(_in_mem_msg_ptr->buff(),insert - _in_mem_msg_ptr->buff()) ;//insert the part of _in_mem_msg_ptr->buff() before the </body>
ad_data.append(ad_content); //add the new html content
ad_data.append(_in_mem_msg_ptr->buff(),insert- _in_mem_msg_ptr->buff(),_in_mem_msg_ptr->dataLen()); //remainder of _in_mem_msg_ptr->buff() from and including </body> to the end
Assuming that char* original is composed by two parts, one starts at 0 while the other (html content after) starts at x you can use strcat and memcpy:
int length = strlen(original)+strlen(newcontent)+1;
char *neworiginal = malloc(sizeof(char)*length);
memset(neworiginal, 0, length);
memcpy(neworiginal,original,x*sizeof(char));
strcat(neworiginal,newcontent);
strcat(neworiginal,original+x);
You need to use strcat() for this problem.
Example =
/* strcat example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[80];
strcpy (str,"these ");
strcat (str,"strings ");
strcat (str,"are ");
strcat (str,"concatenated.");
puts (str);
return 0;
}
Though you need to check the bounds so you can use the bounds variant of strncat().
#include <string.h>
char *strncat(char *restrict s1, const char *restrict s2, size_t n);
Make sure whatever buffer you are appending your string into has enough space to not cause a buffer overflow.
C++ doesn't have + operator for char * strings. You need to use std::string, i.e.
std::string neworiginal = "html content before </body>";
neworiginal += "newhtlminsert";
neworiginal += "..."
Take a look at strstr, strcat and other cstring/string.h functions.
Make sure your char arrays are large enough to hold concatenated strings. Like, you may want to do the following:
char neworiginal[1024];
etc.
The string.h function strcat will concatenate two strings, however it will fail when there is not enough space for the new string. My solution is to make your own version of strcat:
char* myStrCat(const char* str1, const char* str2)
{
char* result;
char* itr1;
char* itr2;
if (str1 == NULL || str2 == NULL)
{
return NULL;
}
result = (char*)malloc(sizeof(char) * (strlen(str1) + strlen(str2) + 1));
itr1 = result;
itr2 = (char*)str1;
while (*itr2 != '\0')
{
*itr1 = *itr2;
itr1++;
itr2++;
}
itr2 = (char*)str2;
while (*itr2 != '\0')
{
*itr1 = *itr2;
itr1++;
itr2++;
}
*itr1 = '\0';
return result;
}
This is kinda ugly, but it gets the job done :)
Attempting to modify the contents of a string literal results in undefined behavior.
You will need to allocate a target buffer (either as an auto variable or by using malloc) that's large enough to hold your final string plus a 0 terminator.
Also, you might want to use sprintf to make life a little easier, such as
sprintf(result, "%s before %s - %s - %s after %s", original,
tag, mycontent, original, tag);
I'm getting the text from editbox and I'd want to get each name separated by enter key like the character string below with NULL characters.
char *names = "Name1\0Name2\0Name3\0Name4\0Name5";
while(*names)
{
names += strlen(names)+1;
}
how would you do the same for enter key (i.e separated by /r/n) ? can you do that without using the std::string class?
Use strstr:
while (*names)
{
char *next = strstr(names, "\r\n");
if (next != NULL)
{
// If you want to use the key, the length is
size_t len = next - names;
// do something with a string here. The string is not 0 terminated
// so you need to use only 'len' bytes. How you do this depends on
// your need.
// Have names point to the first character after the \r\n
names = next + 2;
}
else
{
// do something with name here. This version is 0 terminated
// so it's easy to use
// Have names point to the terminating \0
names += strlen(names);
}
}
One thing to note is that this code also fixes an error in your code. Your string is terminated by a single \0, so the last iteration will have names point to the first byte after your string. To fix your existing code, you need to change the value of names to:
// The algorithm needs two \0's at the end (one so the final
// strlen will work and the second so that the while loop will
// terminate). Add one explicitly and allow the compiler to
// add a second one.
char *names = "Name1\0Name2\0Name3\0Name4\0Name5\0";
If you want to start and finish with a C string, it's not really C++.
This is a job for strsep.
#include <stdlib.h>
void split_string( char *multiline ) {
do strsep( &multiline, "\r\n" );
while ( multiline );
}
Each call to strsep zeroes out either a \r or a \n. Since only the string \r\n appears, every other call will return an argument. If you wanted, you could build an array of char*s by recording multiline as it advances or the return value of strsep.
void split_string( char *multiline ) {
vector< char* > args;
do {
char *arg = strsep( &multiline, "\r\n" );
if ( * arg != 0 ) {
args.push_back( arg );
}
} while ( multiline );
}
This second example is at least not specific to Windows.
Here's a pure pointer solution
char * names = "name1\r\nName2\r\nName3";
char * plast = names;
while (*names)
{
if (names[0] == '\r' && names[1] == '\n')
{
if (plast < names)
{
size_t cch = names - plast;
// plast points to a name of length cch, not null terminated.
// to extract the name use
// strncpy(pout, plast, cch);
// pout[cch] = '\0';
}
plast = names+2;
}
++names;
}
// plast now points to the start of the last name, it is null terminated.
// extract it with
// strcpy(pout, plast);
Since this has the C++ tag, the easiest would probably using the C++ standard library, especially strings and string streams. Why do you want to avoid std::string when you're doing C++?
std::istringstream iss(names);
std::string line;
while( std::getline(iss,line) )
process(line); // do process(line.c_str()) instead if you need to