I have a problem in regards of extracting signed int from string in c++.
Assuming that i have a string of images1234, how can i extract the 1234 from the string without knowing the position of the last non numeric character in C++.
FYI, i have try stringstream as well as lexical_cast as suggested by others through the post but stringstream returns 0 while lexical_cast stopped working.
int main()
{
string virtuallive("Images1234");
//stringstream output(virtuallive.c_str());
//int i = stoi(virtuallive);
//stringstream output(virtuallive);
int i;
i = boost::lexical_cast<int>(virtuallive.c_str());
//output >> i;
cout << i << endl;
return 0;
}
How can i extract the 1234 from the string without knowing the position of the last non numeric character in C++?
You can't. But the position is not hard to find:
auto last_non_numeric = input.find_last_not_of("1234567890");
char* endp = &input[0];
if (last_non_numeric != std::string::npos)
endp += last_non_numeric + 1;
if (*endp) { /* FAILURE, no number on the end */ }
auto i = strtol(endp, &endp, 10);
if (*endp) {/* weird FAILURE, maybe the number was really HUGE and couldn't convert */}
Another possibility would be to put the string into a stringstream, then read the number from the stream (after imbuing the stream with a locale that classifies everything except digits as white space).
// First the desired facet:
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
// everything is white-space:
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
// except digits, which are digits
std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
// and '.', which we'll call punctuation:
rc['.'] = std::ctype_base::punct;
return &rc[0];
}
};
Then the code to read the data:
std::istringstream virtuallive("Images1234");
virtuallive.imbue(locale(locale(), new digits_only);
int number;
// Since we classify the letters as white space, the stream will ignore them.
// We can just read the number as if nothing else were there:
virtuallive >> number;
This technique is useful primarily when the stream contains a substantial amount of data, and you want all the data in that stream to be interpreted in the same way (e.g., only read numbers, regardless of what else it might contain).
Related
I want to send GPG encrypted data via GET request of known format.
Issue #1: Data block size in the request is limited (4096 symbols), and it is not enough for a typical GPG message. So, I need to chunk it.
Issue #2: Chunks may be sent in the wrong order. Each chunk must have a unique message ID and serial number, so the messages can be put together.
GPG has the method to send encrypted data in text format (armoring). RFC 2440 standard allows chunking armored messages:
BEGIN PGP MESSAGE, PART X/Y
Used for multi-part messages, where the armor is split amongst Y
parts, and this is the Xth part out of Y.
BEGIN PGP MESSAGE, PART X
Used for multi-part messages, where this is the Xth part of an
unspecified number of parts. Requires the MESSAGE-ID Armor Header
to be used.
But, unfortunately, I've found no evidence that this feature is implemented in GPG.
And no word about chunking of public keys, which, actually, can be huge too.
So I turned down the idea of using native GPG armors for chunking.
My current home-made solution: binary encrypted data are splitted into chunks, then each chunk is put into a block, which contains UUID (MessageID analog), the serial number of the block, the total number of blocks, and CRC checksum of the block.
Like that:
[ UUID ][ Number ][ Total ][ Chunk of encrypted data ][ Checksum ]
Putting the message together out of that blocks is a bigger challenge, but doable as well.
But I want more clear solution, preferably on C++.
Could you help me?
Qt provides very simple methods for data serialization. I created a class to chunk, store, and rebuild binary data, and for now I don't think I need something more simple.
But, if someone knows a better solution, please share it with me.
#include <QByteArrayView>
#include <QDataStream>
#include <QException>
#include <QUuid>
enum CHUNKER {
MESSAGE_READY = 0,
BLOCK_ADDED
};
struct ChunkedMessage {
QUuid UUID;
QByteArray Data;
};
class Chunker {
public:
Chunker();
~Chunker();
static quint16 GetChecksum(QByteArray *Block);
static QByteArrayList ArmorData(QByteArray *Data, qsizetype *ChunkSize);
CHUNKER AddBlock(QByteArray *Block, ChunkedMessage *Message);
private:
struct MessageBlock {
QUuid UUID;
quint32 Number;
quint32 Total;
QByteArray Data;
};
QMap<QUuid, quint32> Sizes;
QMap<QUuid, QMap<quint32, Chunker::MessageBlock>*> Stack;
MessageBlock DearmorChunk(QByteArray *Block);
bool CheckIntegrity(QUuid *UUID, QByteArray *Reconstructed);
};
Chunker::Chunker() { }
Chunker::~Chunker() { }
quint16 Chunker::GetChecksum(QByteArray *Block) { return qChecksum(QByteArrayView(*Block), Qt::ChecksumIso3309); }
QByteArrayList Chunker::ArmorData(QByteArray *Data, qsizetype *ChunkSize) {
QByteArrayList Result;
QUuid UUID = QUuid::createUuid();
qsizetype RealChunkSize = (*ChunkSize) - sizeof(UUID.toRfc4122()) - sizeof(quint32) - sizeof(quint32) - sizeof(quint16);
const quint32 ChunkCount = ((*Data).length() / RealChunkSize) + 1;
for (auto Pos = 0; Pos < ChunkCount; Pos++) {
QByteArray Block;
QDataStream Stream(&Block, QIODeviceBase::WriteOnly);
Stream << UUID.toRfc4122() << (Pos + 1) << ChunkCount << (*Data).mid(Pos * RealChunkSize, RealChunkSize);
Stream << Chunker::GetChecksum(&Block);
Result.push_back(Block);
}
return Result;
}
Chunker::MessageBlock Chunker::DearmorChunk(QByteArray *Block) {
Chunker::MessageBlock Result;
QDataStream Stream(Block, QIODeviceBase::ReadOnly);
QByteArray ClearBlock = (*Block).chopped(sizeof(quint16));
QByteArray BytesUUID;
quint16 Checksum;
Stream >> BytesUUID >> Result.Number >> Result.Total >> Result.Data >> Checksum;
Result.UUID = QUuid::fromRfc4122(QByteArrayView(BytesUUID));
if (Chunker::GetChecksum(&ClearBlock) != Checksum) throw std::runtime_error("Checksums are not equal");
return Result;
}
bool Chunker::CheckIntegrity(QUuid *UUID, QByteArray *Reconstructed) {
quint32 Size = this->Sizes[*UUID];
if (this->Stack[*UUID]->size() > Size) throw std::runtime_error("Corrupted message blocks");
if (this->Stack[*UUID]->size() < Size) return false;
for (quint32 Counter = 0; Counter < Size; Counter++) {
if (!(this->Stack[*UUID]->contains(Counter + 1))) return false;
(*Reconstructed).append((*(this->Stack[*UUID]))[Counter + 1].Data);
}
return true;
}
CHUNKER Chunker::AddBlock(QByteArray *Block, ChunkedMessage *Message) {
Chunker::MessageBlock DecodedBlock = Chunker::DearmorChunk(Block);
if (!this->Sizes.contains(DecodedBlock.UUID)) {
this->Sizes[(QUuid)DecodedBlock.UUID] = (quint32)DecodedBlock.Total;
this->Stack[(QUuid)DecodedBlock.UUID] = new QMap<quint32, Chunker::MessageBlock>;
}
(*(this->Stack[DecodedBlock.UUID]))[(quint32)(DecodedBlock.Number)] = Chunker::MessageBlock(DecodedBlock);
QByteArray ReconstructedData;
if (this->CheckIntegrity(&DecodedBlock.UUID, &ReconstructedData)) {
(*Message).UUID = (QUuid)(DecodedBlock.UUID);
(*Message).Data = (QByteArray)ReconstructedData;
this->Sizes.remove(DecodedBlock.UUID);
delete this->Stack[DecodedBlock.UUID];
this->Stack.remove(DecodedBlock.UUID);
return CHUNKER::MESSAGE_READY;
}
return CHUNKER::BLOCK_ADDED;
}
I'm writing some code to take in a string, turn it into a char array and then print back to the user (before passing to another function).
Currently the code works up to dat.toCharArray(DatTim,datsize); however, the pointer does not seem to be working as the wile loop never fires
String input = "Test String for Foo";
InputParse(input);
void InputParse (String dat)
//Write Data
datsize = dat.length()+1;
const char DatTim[datsize];
dat.toCharArray(DatTim,datsize);
//Debug print back
for(int i=0;i<datsize;i++)
{
Serial.write(DatTim[i]);
}
Serial.println();
//Debug pointer print back
const char *b;
b=*DatTim;
while (*b)
{
Serial.print(*b);
b++;
}
Foo(*DatTim);
I can't figure out the difference between what I have above vs the template code provided by Majenko
void PrintString(const char *str)
{
const char *p;
p = str;
while (*p)
{
Serial.print(*p);
p++;
}
}
The expression *DatTim is the same as DatTim[0], i.e. it gets the first character in the array and then assigns it to the pointer b (something the compiler should have warned you about).
Arrays naturally decays to pointers to their first element, that is DatTim is equal to &DatTim[0].
The simple solution is to simply do
const char *b = DatTim;
I need to show a base64 key in a TMemo. Unfortunately, it is impossible to show this base64 string appropriately: it is cut off at every '/' by a Carriage return, or at any '+' where it systematically starts a new line !
I tried everything in my knowledge to make this string in one long phrase (without carriage returns), but unsucessfully.
How is it possible to obtain a flat string in base64 (without carriage returns), if possible resizable automatically when the form and TMemo is resized ?
Many thanks.
For those who are interested, the code below: a TForm with a TMemo (memo). This solution works for me for a flat Base64 string. At last no longer string cut-off at every / or +.
Maybe the solution below needs to be tuned, but it works enough for me. Of course, before to treat the b64 string in an application, it needs to be filtered to eliminate CR-LF but that's OK.
I use the events: OnKeyDown, OnResize, OnPainting of the TMemo.
I wrote a specific function formatMemo(..) which does the job of aligning the lines appropriately.
The code accepts only true B64 characters, and filters faulty characters if any.
#define IS_B64(c) (isalnum(c) || (c == '/') || (c == '+') || (c == '='))
//Adjustments work for Courier New, standard size:
const float FW=7.2;//Font width
const diff=25;//Room for vert. scroll bar
//Gives the number of characters in one line of the TMemo:
// width : width in pixels where to put the line of chars
// font_sz : the average width of a character
// returns the number of characters by line of the TMemo
inline int nchars(int width, float font_sz)
{
return int(float(width-diff)/font_sz);
}//nchars
//---------------------------------------------------------------------------
//Formats the memo to a certain length of characters:
// *p : the memo to format
// nc : the number of characters for each line.
void formatMemo(TMemo *p, int nc)
{
if(p==0) return;
AnsiString src, dest;//UnicodeString is less fast...
//Filter everything as B64 only:
for(int i=1; i<=p->Text.Length(); ++i) {//Indexing is "1-based" like on Delphi (except on mobiles)
if(IS_B64(p->Text[i])) dest += p->Text[i];
}
p->Lines->Clear();//Erases everyting
int length=dest.Length(), units=length/nc, remain=length%nc;
for( int k=0 ; k<units ; ++k) {
p->Lines->Append( dest.SubString(1+k*nc, nc) );
}
if(remain) {
p->Lines->Append( dest.SubString(1+units*nc, remain) );
}
}//formatMemo
//---------------------------------------------------------------------------
void __fastcall TForm1::memoKeyDown(TObject *Sender, WORD &Key, System::WideChar &KeyChar,
TShiftState Shift)
{
//This event is triggered before the character is sent in Text.
//Saves caret position:
TCaretPosition p={memo->CaretPosition.Line, memo->CaretPosition.Pos};
memo->Tag=0;//Don't do a format.
if(Key==0 && !IS_B64(KeyChar))//Printable KeyChar
{
//Changes the entry into '0':
KeyChar='0';
KeyDown(Key,KeyChar,Shift);
//Put a backspace to erase:
Key=vkBack; KeyChar=0;
KeyDown(Key,KeyChar,Shift);
}
else memo->Tag=1;//Programs a format in the OnPainting
memo->SetFocus();
memo->CaretPosition=p;//Repositions the caret
}
//---------------------------------------------------------------------------
//In case of resize, reformat the TMemo
void __fastcall TForm1::memoResize(TObject *Sender)
{
formatMemo(memo, nchars(memo->Width,FW));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::memoPainting(TObject *Sender, TCanvas *Canvas, const TRectF &ARect)
{
//We will use the Tag of the memo as a parameter, to plan a reformat.
if(memo->Tag){//A format is asked by OnKeyDown.
TCaretPosition p={memo->CaretPosition.Line, memo->CaretPosition.Pos};
formatMemo(memo, nchars(memo->Width,FW));
memo->SetFocus();
memo->CaretPosition=p;
memo->Tag=0;//Done
}
}
//---------------------------------------------------------------------------
I found this code below on the internet which is suppose to count the sentences on an 8051 MCU.
Can someone please explain to me what is exactly happening where there are question marks.
Any kind of help would be highly appreciated.
#include<string.h>
char code *text=" what is a program? that has, a a lot of errors! When " ;
char code *text1=" you compile. this file, uVision. reports a number of? ";
char code *text2=" problems that you! may interactively correct. " ; //Null characters are also included in array!!!
void count ( char pdata* , char pdata*);
void main (void){
char pdata Nw,Ns;
char data TextNw[2],TextNs[2];
count(&Nw, &Ns); // call subroutine
TextNw[0]=Nw/10; //?????????????????????????????????
TextNw[1]=Nw%10; //?????????????????????????????????
TextNs[0]=Ns/10; //?????????????????????????????????
TextNs[1]=Ns%10; //?????????????????????????????????
while(1);
}
void count ( char pdata *Nw, char pdata *Ns ){
unsigned char N, i, ch;
typedef enum {idle1, idle2} state; //?????????????????????????????????
state S; // begining state
P2=0x00; // pdata bank definition it must be performed first!!
*Ns=*Nw=0; // without proper start-up there is no initialisation, initialise now!!
S=idle1; // beginning state
N=strlen(text)+strlen(text1)+strlen(text2)+3; //????????????? + 3 to acount 3 Null characters!
P2=0x00; // pdata bank definition
for(i=0;i!=N;i++){
ch=text[i]; // take a caharacter from the text
switch (S)
{
case (idle1):{
if (ch==0) break; // skip NULL terminating character!
if (ch!=' '){
S=idle2;
(*Nw)++;
}
break;
}
case(idle2):{
if (ch==0) break; // skip NULL terminating character!
if((ch==' ')||(ch==','))S=idle1;
else if ((ch=='?')||(ch=='.')||(ch=='!')){
S=idle1;
(*Ns)++;
}
break;
}
}
}
}
This program does 2 things in conjunction - counts number of sentences in the text and counts the number of words in the text. Once the counting is done, the results are stored in 2-char arrays. For example, for 57 words in 3 sentences the results will be stored as this: TextNw = {'5','7'} and TextNs = {'0','3'}.
The variable N contains the full length of the text with the addition of 3 null terminating characters (one per sentence).
The algorithm simultaneously counts words and sentences. In idle1 state the counting is in word-counting mode. In idle2 state the counting is in sentence-counting mode. The modes are interchanged according to current character being read - if delimiter is encountered, the appropriate counter is increased.
I've got a form with a Listbox which contains lines of four words.
When I click on one line, these words should be seen in four different textboxes.
So far, I've got everything working, yet I have a problem with chars converting.
The string from the listbox is a UnicodeString but the strtok uses a char[].
The compiler tells me it "Cannot Convert UnicodeString to Char[]". This is the code I am using for this:
{
int a;
UnicodeString b;
char * pch;
int c;
a=DatabaseList->ItemIndex; //databaselist is the listbox
b=DatabaseList->Items->Strings[a];
char str[] = b; //This is the part that fails, telling its unicode and not char[].
pch = strtok (str," ");
c=1;
while (pch!=NULL)
{
if (c==1)
{
ServerAddress->Text=pch;
} else if (c==2)
{
DatabaseName->Text=pch;
} else if (c==3)
{
Username->Text=pch;
} else if (c==4)
{
Password->Text=pch;
}
pch = strtok (NULL, " ");
c=c+1;
}
}
I know my code doesn't look nice, pretty bad actually. I'm just learning some programming in C++.
How can I convert this?
strtok actually modifies your char array, so you will need to construct an array of characters you are allowed to modify. Referencing directly into the UnicodeString string will not work.
// first convert to AnsiString instead of Unicode.
AnsiString ansiB(b);
// allocate enough memory for your char array (and the null terminator)
char* str = new char[ansiB.Length()+1];
// copy the contents of the AnsiString into your char array
strcpy(str, ansiB.c_str());
// the rest of your code goes here
// remember to delete your char array when done
delete[] str;
This works for me and saves me converting to AnsiString
// Using a static buffer
#define MAX_SIZE 256
UnicodeString ustring = "Convert me";
char mbstring[MAX_SIZE];
wcstombs(mbstring,ustring.c_str(),MAX_SIZE);
// Using dynamic buffer
char *dmbstring;
dmbstring = new char[ustring.Length() + 1];
wcstombs(dmbstring,ustring.c_str(),ustring.Length() + 1);
// use dmbstring
delete dmbstring;