Programowanie w języku Delphi » Artykuły

Konwersja liczb na string i vice versa

  • 2013-11-27 23:39
  • 5 komentarzy
  • 14431 odsłon
  • Oceń ten tekst jako pierwszy



Wstęp. Jak to było dawniej


Bardzo często podczas pisania aplikacji zachodzi potrzeba konwersji zmiennej tekstowej na jej numeryczny odpowiednik i vice versa. Wszelkiego typu kontrolki edycyjne, etykiety i inne wymagają łańcucha znaków, natomiast CPU do swoich obliczeń potrzebuje wartości numerycznej. Czy nam się to podoba czy nie należy dokonać konwersji.

W czasach kiedy dominował Dos i Turbo Pascal oraz C programiści nie mieli zbyt dużego wyboru w funkcjach konwertujących. Pascal oferował tylko dwie, a mianowicie: Val oraz Str. Ich odpowiednikami w C były kolejno: atoi i itoa i pochodne dla różnych typów atof, atol, ltoa. Deklaracje owych funkcji (procedur) wyglądają następująco:

Pascal/Delphi

procedure Val(S; var V; var Code: Integer);


Procedura ta operuje na liczbach całkowitych i rzeczywistych. Opis poszczególnych parametrów jest następujący:
- S jest sekwencją znaków; Do poprawnej konwersji musi zawierać znaki + - , . 0..9.
- V jest zwracaną wartością numeryczną po konwersji zmiennej S. Jeżeli V ma zwrócić wynik całkowitoliczbowy, zmienna S nie może zawierać , oraz ..
- Code Zwraca pozycję wystąpienia nielegalnego znaku w zmiennej S, który uniemożliwił konwersję.

Przykłady użycia:

Delphi
Var Value :Integer;
Val('1234', Value, Code); // Value = 1234, Code = 0
Val('1.234', Value, Code); // Value = 0, Code = 2
Val('abcd', Value, Code); // Value = 0, Code = 1


C/C++
Prototyp

int atoi(const char *s);
double atof(const char *s);
long atol(const char *s);

Jeżeli operacja konwersji zakończy się sukcesem wówczas funkcje zwracają wartość odpowiadającą zmiennej s, w przeciwnym razie zwracają wartość 0.

Przykłady użycia:

Int n;
n= atoi("1234"); // n = 1234
n= atoi("1s"); // n= 0

Wiemy już jak zamienić łańcuch znaków na liczbę, teraz kolej na konwersję liczba -> łańcuch.

Nie ma problemu jeżeli używamy procedur Write/WriteLn z Pascala oraz printf z C. Obie procedury tolerują zapis bez konwersji. Problem zaczyna się gdy używamy np. TextOut (Pascal) textout (C/C++). Tutaj zapis

Var alfa :Byte;
TextOut('alfa = ', alfa);  // lub
TextOut('alfa = '+alfa);

wywoła u kompilatora niestrawność. Dlatego udostępniono programistą procedurę Str w Pascalu i ltoa, itoa w C/C++.

Deklaracja w Pascalu jest następująca:

procedure Str(X [: Width [: Decimals ]]; var S);

Jej używanie jest bardzo podobne jak w przypadku Val z tą różnicą, że dla zmiennej X (która może być typu całkowitego i rzeczywistego) można zastosować formatowanie: wartość_liczbowa:ilość_cyfr:po_przecinku. Procedury tej używamy w następujący sposób:

Var s :string;
Str(1234, s); // s = '1234'
Str(PI:10:3, s); // s = 3.141

W C/C++ sprawa ma się nieco odmiennie:

char * ltoa(long value, char * string, int radix);
char *itoa(int value, char *string, int radix);

Gdzie:

  • value - zmienna liczbowa
  • string - wynik konwersji
  • radix - system liczbowy, musi zawierać się pomiędzy 2..36, jeżeli będzie poza przedziałem wówczas radix przyjmie wartość 10 (co de facto odpowiada dziesiętnemu systemowi liczbowemu). Funkcje zwracają wartość w postaci ASCII.

przykład

   int number = 12345;
   char string[25];
 
   itoa(number, string, 10);



Ewolucja i rozwój możliwości


Czasy się jednak zmieniają (kompilatory również). Obecnie używa się Delphi i BCB. Dają one programistom większy wybór jeżeli chodzi o konwersję pozostając nadal w zgodzie z poprzednikami, dlatego nagłówki i sposoby w/w procedur nie uległy zmianie. Mamy tu do dyspozycji szereg przydatnych funkcji: IntToStr, FloatToStr, FloatToStrF, FloatToCurr, IntToHex, IntToStrDef, TryStrToInt, TryStrToFloat, StrToColor, StrToInt, StrToFloatDef i wiele innych. Przejdźmy zatem do omówienia każdej z nich. Należy dodać, że funkcje są przeciążane w celu optymalizacji działań na określonych typach.


Konwersja liczby na string


Składnia Delphi:

function IntToStr(Value: Integer): string; overload;
function IntToStr(Value: Int64): string; overload;

Składnia C++ :

extern PACKAGE AnsiString __fastcall IntToStr(int Value);
extern PACKAGE AnsiString __fastcall IntToStr(__int64 Value);

Opis:

Konwersja typu Integer na String. Value jest to wartość konwertowana. W przypadku gdy konwersja nie była możliwa Windows zgłasza EConvertError, który należy przechwycić i odpowiednio obsłużyć.

Składnia Delphi:

function IntToHex(Value: Integer; Digits: Integer): string; overload;
function IntToHex(Value: Int64; Digits: Integer): string; overload;

Składnia C++ :

extern PACKAGE AnsiString __fastcall IntToHex(int Value, int Digits);
extern PACKAGE AnsiString __fastcall IntToHex(__int64 Value, int Digits);

Opis:

Konwersja zmiennej Integer na string w reprezentacji szesnastkowej gdzie:
  • Value - zmienna konwertowana,
  • digits - minimalna długość cyfry po konwersji
W przypadku niepowodzenia generowany jest wyjątek EConvertError.


Składnia Delphi:

function FloatToStr(Value: Extended): string; overload;
function FloatToStr(Value: Extended; const FormatSettings: TFormatSettings): string; overload;

Składnia C++ :

extern PACKAGE AnsiString __fastcall FloatToStr(Extended Value);
extern PACKAGE AnsiString __fastcall FloatToStr(Extended Value, const TFormatSettings FormatSettings);

Opis:

Konwersja zmiennych rzeczywistych na String. Mamy tu dwie odmiany: zwykła i z możliwością ustalenia formatu wynikowego. Stała FormatSettings wygląda następująco:

type
  TFormatSettings = record
    CurrencyFormat: Byte;
    NegCurrFormat: Byte;
    ThousandSeparator: Char;
    DecimalSeparator: Char;
    CurrencyDecimals: Byte;
    DateSeparator: Char;
    TimeSeparator: Char;
    ListSeparator: Char;
    CurrencyString: string;
    ShortDateFormat: string;
    LongDateFormat: string;
    TimeAMString: string;
    TimePMString: string;
    ShortTimeFormat: string;
    LongTimeFormat: string;
    ShortMonthNames: array[1..12] of string;
    LongMonthNames: array[1..12] of string;
    ShortDayNames: array[1..7] of string;
    LongDayNames: array[1..7] of string;
    TwoDigitYearCenturyWindow: Word;
  end;

W przypadku niepowodzenia generowany wyjątek EConvertError.

Składnia Delphi:

function FloatToStrF(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): string; overload;
function FloatToStrF(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer; const FormatSettings: TFormatSettings
): string; overload;

Składnia C++ :

extern PACKAGE AnsiString __fastcall FloatToStrF(Extended Value, TFloatFormat Format, int Precision, int Digits);
extern PACKAGE AnsiString __fastcall FloatToStrF(Extended Value, TFloatFormat Format, int Precision, int Digits, const TFormatSettings FormatSettings);

Opis:

Konwersja zmiennych rzeczywistych na zmienne tekstowe z możliwością ustalenia liczb znaczących i precyzji wyniku.
  • Value - zmienna konwertowana
  • Format - styl reprezentacji zmiennej po konwersji. Przyjmuje następujące wartości:

Format Definicja
ffGeneral Generalny format liczbowy. Zmienna konwertowana jest na najkrótszą możliwą postać dziesiętną używająć formatu naukowego lub zwykłego. Zbędne zera są usuwane. W przypadku gdy x = 0.00001 wartość jest wyświetlana normalnie. Poniżej tego progu wyświetlana jest w formacie naukowym.
ffExponent Format naukowy-wykładniczy. Zmienna jest konwertowana na string postaci d.ddd...E+dddd. Jeżeli wartość jest mniejsza od zera to String zaczyna się od znaku minus. Całkowita liczba cyfr przed obliczeniem wykładnika jest ustalana parametrem Precision.
ffFixed Zmodyfikowany format wynikowy. Wartość konwertowana jest na ddd.ddd...;. Liczba miejsc po przecinku musi być w zakresie 0..18. W przypadku zakresy większego liczba będzie wyświetlona w formacie naukowym.
ffNumber Format numeryczny. Wartość jest konwertowana na d,ddd,ddd.ddd... Generalnie to samo co ffFixed z dodatkowymi separatorami tysięcznymi.
ffCurrency Konwersja na format walutowy.

  • Precision - liczba cyfr znaczących
  • Digits - liczba cyfr po przecinku
W przypadku niepowodzenia generowany wyjątek EConvertError.

Składnia Delphi:

function FloatToCurr(const Value: Extended): Currency;

Składnia C++ :

extern PACKAGE System::Currency __fastcall FloatToCurr(const Extended Value);

Opis:

Konwersja liczby zmiennoprzecinkowej na format walutowy.


Konwersja stringu na liczbę


Analogicznie wyglądają funkcje do konwersji zmiennej tekstowej na wartość numeryczną:

Składnia Delphi:

function StrToInt(const S: string): Integer;
function StrToInt64(const S: string): Int64;
function StrToFloat(const S: string): Extended; overload;
function StrToFloat(const S: string; const FormatSettings: TFormatSettings): Extended; overload;
function StrToCurr(const S: string): Currency; overload;
function StrToCurr(const S: string; const FormatSettings: TFormatSettings): Currency; overload;

Składnia C++ :

extern PACKAGE int __fastcall StrToInt(const AnsiString S);
extern PACKAGE __int64 __fastcall StrToInt64(const AnsiString S);
extern PACKAGE Extended __fastcall StrToFloat(const AnsiString S);
extern PACKAGE Extended __fastcall StrToFloat(const AnsiString S, const TFormatSettings FormatSettings);
extern PACKAGE System::Currency __fastcall StrToCurr(const AnsiString S);
extern PACKAGE System::Currency __fastcall StrToCurr(const AnsiString S, const TFormatSettings FormatSettings);

Opis:

W przypadku gdy konwersja nie była możliwa wszystkie generują wyjątek EConvertError.


Konwersja a ustalenie wartości domyślnej


W przypadku gdy nie chcemy obsługiwać wyjątków możemy użyć funkcji z grupy poniżej. Wszystkie one mają możliwość ustalenia domyślnej wartości zwracanej w przypadku gdy konwersja nie będzie możliwa:

Składnia Delphi:

function StrToIntDef(const S: string; const Default: Integer): Integer;
function StrToCurrDef(const S: string; const Default: Currency): Currency; overload;
function StrToCurrDef(const S: string; const Default: Currency; const FormatSettings: TFormatSettings): Currency; overload;
function StrToFloatDef(const S: string; const Default: Extended): Extended; overload;
function StrToFloatDef(const S: string; const Default: Extended; const FormatSettings: TFormatSettings): Extended; overload;

Składnia C++ :

extern PACKAGE int __fastcall StrToIntDef(const AnsiString S; const int Default);
extern PACKAGE System::Currency __fastcall StrToCurrDef(const AnsiString S, const System::Currency Default);
extern PACKAGE System::Currency __fastcall StrToCurrDef(const AnsiString S, const System::Currency Default, const TFormatSettings FormatSettings);
extern PACKAGE Extended __fastcall StrToFloatDef(const AnsiString S; const Extended Default);
extern PACKAGE Extended __fastcall StrToFloatDef(const AnsiString S; const Extended Default, const TFormatSettings FormatSettings);

Opis:

W miejsce Default przypisujemy wartość jaką ma zwrócić funkcja w przypadku niepomyślnej konwersji.


Czy dany ciąg znaków jest liczbą?


Często stajemy przed problemem sprawdzenia czy dany ciąg znaków jest liczbą. Tu z pomocą przychodzą nam funkcje:

Składnia Delphi:

function TryStrToInt(const S: string; out Value: Integer): Boolean;
function TryStrToInt64(const S: string; out Value: Int64): Boolean;
function TryStrToFloat(const S: string; out Value: Extended): Boolean; overload;
 
function TryStrToFloat(const S: string; out Value: Double): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Single): Boolean; overload;
 
function TryStrToFloat(const S: string; out Value: Extended; const FormatSettings: TFormatSettings): Boolean; overload;
 
function TryStrToFloat(const S: string; out Value: Double; const FormatSettings: TFormatSettings): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Single; const FormatSettings: TFormatSettings): Boolean; overload;
function TryStrToCurr(const S: string; out Value: Currency): Boolean; overload;
function TryStrToCurr(const S: string; out Value: Currency; const FormatSettings: TFormatSettings): Boolean; overload;

Składnia C++ :

extern PACKAGE bool __fastcall TryStrToInt(const AnsiString S, int &Value);
extern PACKAGE bool __fastcall TryStrToInt64(const AnsiString S, __int64 &Value);
extern PACKAGE bool __fastcall TryStrToFloat(const AnsiString S, Extended &Value);
 
extern PACKAGE bool __fastcall TryStrToFloat(const AnsiString S, double &Value);
extern PACKAGE bool __fastcall TryStrToFloat(const AnsiString S, float &Value);
 
extern PACKAGE bool __fastcall TryStrToFloat(const AnsiString S, Extended &Value, const TFormatSettings FormatSettings);
 
extern PACKAGE bool __fastcall TryStrToFloat(const AnsiString S, double &Value, const TFormatSettings FormatSettings);
extern PACKAGE bool __fastcall TryStrToFloat(const AnsiString S, float &Value, const TFormatSettings FormatSettings);
extern PACKAGE bool __fastcall TryStrToCurr(const AnsiString S, System::Currency &Value);
extern PACKAGE bool __fastcall TryStrToCurr(const AnsiString S, System::Currency &Value, const TFormatSettings FormatSettings);

Opis:

W przypadku pomyślnej konwersji wunkcja zwraca wartość True, w przeciwnym razie False.


Przykłady użycia funkcji w kodzie programu


Składnia Delphi\Pascal

Var 
 i :LongInt;
s :string;
 
i := StrToInt(Edit1.Text);
i := StrToInt('123');
s := intToStr(i);
s := IntToStr(123);
 
i := StrToIntDef(s, 0);
if TryStrToInt(s, i) then
  ShowMessage(s + ' jest poprawnym formatem liczbowym');

Składnia C\C++

long i;
 
i = StrToInt(Edit1->Text);
Edit1->Text = IntToStr(i);
 
If !(TryStrToInt(Edit1->Text, i) ShowMessage("Błąd konwersji");</cpp>
 
= Przechwytywanie wyjątku EConvertError =
 
Składnia Delphi\Pascal
 
<code=delphi>try
 i := StrToInt(Edit1.Text);
except
on Ex :EconvertError do 
 begin
  { obsługa wyjątku }
 end;

Składnia C\C++ :

try
 
{
 i = StrToInt(Edit1->Text);    
}
catch (EConvertError &ConvertErr)
{
    // obsługa wyjątku
}

5 komentarzy

Brak avatara
gogo 2013-11-13 11:33

Tekst niewidiczny przez reklamy

BDxXx 2008-03-20 15:31

StrToFloat przy episaniu  literek moze spowodowac Floating point overflow, a tego juz tak prosto nie da sie przechwycic:(

Ktos 2006-11-17 09:05

Miałem ochotę zapytać się jak można przekonwertować liczbę na "vice versa" ;)

Oleksy_Adam 2006-11-16 21:51

@ŁF - poprawione

ŁF 2006-11-16 21:40

poprawcie apostrofy przy stringach