Strona 1 z 2
StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 15:26
przez manin
Witam.
Dopiero co zacząłem pracę z C++ Builder i natknąłem się na problem, z którym nie umiem sobie poradzić.
Stworzony przeze mnie StringGrid w przechowuje w komórkach jednej z kolumn ciąg liczb rozdzielonych spacjami, np:
1 4 15 62 8
Dodatkowo ilość liczb w takim Stringu nie zawsze jest jednakowa.
W jaki sposób można (najprościej i najczytelniej dla laika) liczby z takiego ciągu zapisać w jednowymiarowej tablicy?
Dodatkowo, czy istnieje sposób, aby każdy znak, niebędący cyfrą, który przez nieuwagę użytkownika znalazłby się w komórce, zastąpić spacją?
Z góry dziękuję za wskazówki.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 16:05
przez Mironas
Przepisanie liczb ze stringa do tablicy, zakładając dla uproszczenia, że w stringu nie ma więcej niż 10 liczb można zrobić np tak:
TStrings* lista = new TStringList();
lista->LineBreak = " ";
lista->Text = "1 2 5 10 15 25";
int tab[10]; // max 10 liczb
for (int i=0 ; i<lista->Count ; i++)
tab[i] = lista->Strings[i].ToInt();
delete lista;
Jeśli nie wiesz ile maksymalnie może być liczb to musisz tworzyć tablicę dynamicznie.
Zamiana w tekście znaków innych niż cyfry na spacje:
String tekst = "1a2 5 10 z15 25x";
for (int i=1 ; i<=tekst.Length() ; i++)
if ( tekst[i]<'0' || tekst[i]>'9' )
tekst[i] = ' '; // tutaj spacja
Przy takich operacjach pomocna może też być funkcja
StringReplace(...).
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 16:40
przez manin
Dzięki za szybką odpowiedź, jednak chyba robię coś nie tak, bo przy kompilacji wyskakuje błąd 'LineBreak' is not member of 'TStrings'.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 17:07
przez Cyfrowy Baron
Wszystko robisz dobrze, tylko w C++Builder 6 TStringList nie ma metody LineBreak. W podanych niżej przykładach użyto tej metody by łamać tekst po każdej spacji, czyli taki zapis:
po użyciu LineBreak będzie wyglądał tak:
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 18:22
przez manin
W takim razie jakiej metody mógłbym użyć, ewentualnie w jaki sposób zmodyfikować tę, aby działała w "szóstce"?
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 19:01
przez Mironas
Dla BCB6 można tak:
TStrings* lista = new TStringList();
String tekst = "1 2 5 10 15 25";
// zamiana spacji na znaki końca wiersza
lista->Text = StringReplace(tekst, " ", "\r\n", TReplaceFlags() << rfReplaceAll);
int tab[10];
for (int i=0 ; i<lista->Count ; i++)
tab[i] = lista->Strings[i].ToInt();
delete lista;
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 19:01
przez Cyfrowy Baron
Trzeba parsować lub posłużyć się regex'em. Napiszę w wolnej chwili parsowanie, ale nie dziś.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 19:08
przez polymorphism
Regex do tego?! Niech użyje klasy
istringstream.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 20:07
przez Cyfrowy Baron
polymorphism napisał(a):Niech użyje klasy istringstream.
A to mi akurat nie przyszło do głowy.
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
AnsiString text = "1 14 19 20";
istringstream iSS( text.c_str() ); /* lub iSS( StringGrid1->Cell[x][y].c_str() ) */
int n;
while(iSS >> n)
{
ListBox1->Items->Add(n); /* tutaj przepisujesz ze zmiennej n gdzie ci potrzeba */
}
Tyle, że przeszukiwanie zostanie przerwane gdy napotka tekst zamiast liczby. Można więc posłużyć się metodą
isdigit:
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include <sstream>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
using namespace std;
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString text = "1 14 text 19 20";
istringstream iSS( text.c_str() );
char *buf;
while(iSS >> buf)
{
if( isdigit( (unsigned char)*buf ) )
ListBox1->Items->Add(buf);
}
}
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 20:47
przez manin
Dziękuję bardzo wszystkim. Dzięki wam mogę ruszać dalej. Kluczem okazał się isdigit. Nie miałem pojęcia o istnieniu takiej funkcji. Z resztą sobie już poradziłem.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 20:49
przez polymorphism
char *buf; //<--- na co wskazuje?
while(iSS >> buf) { ... }
Zamiast kombinować z gołymi wskaźnikami, użyj po prostu
std::
stringa, i wtedy testuj pierwszy znak.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 20:51
przez Cyfrowy Baron
Ale on pracuje na tabeli StringGrid i typie AnsiString, więc jak da std::string to będzie musiał kombinować z konwersją.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 20:56
przez polymorphism
Z tego co pamiętam, to nie - są zdefiniowane operatory << >> dla AnsiStringa.
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 21:01
przez Cyfrowy Baron
Nie wiem o co Tobie chodziło w ostatniej wypowiedzi, ale można też ze string. W ten sposób pozbędę się pustego wskaźnika:
AnsiString text = "1 14 text 19 20";
istringstream iSS( text.c_str() );
string buf;
while(iSS >> buf)
{
if( isdigit( *buf.c_str() ) )
ListBox1->Items->Add( buf.c_str() );
}
Można by też od razu na AnsiString:
AnsiString text = "1 14 text 19 20";
istringstream iSS( text.c_str() );
AnsiString buf;
while(iSS >> buf.c_str())
{
if( isdigit( *buf.c_str() ) )
ListBox1->Items->Add( buf );
}
Re: StrToInt dla kilku liczb
Napisane:
poniedziałek, 2 grudnia 2013, 21:27
przez polymorphism
while(iSS >> buf.c_str())
To jest zła konstrukcja. Zawartość zwrócona przez
c_str jest
tylko do odczytu.
Nie wiem o co Tobie chodziło w ostatniej wypowiedzi (...)
O to mi chodziło, że
AnsiString ma zdefiniowane operatory << >> dla strumieni standardowych, dzięki czemu nic nie musisz konwertować.
Z dokumentacji:
To utilize the C++ streaming operators (<< and >>) with AnsiString, you must use #include <iostream> or #define VCL_IOSTREAM before #include <dstring.h>. This occurs automatically if you include vcl.h or system.h and defines the operators as follows:
ostream& operator << (ostream& os, const AnsiString& arg);
istream& operator >> (istream& is, AnsiString& arg);