Konwersja liczb na string i vice versa
Oleksy_Adam
1 Wstęp. Jak to było dawniej
2 Ewolucja i rozwój możliwości
3 Konwersja liczby na string
4 Konwersja stringu na liczbę
5 Konwersja a ustalenie wartości domyślnej
6 Czy dany ciąg znaków jest liczbą?
7 Przykłady użycia funkcji w kodzie programu
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 **[[Delphi/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
```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
}
StrToFloat przy episaniu literek moze spowodowac Floating point overflow, a tego juz tak prosto nie da sie przechwycic:(
Miałem ochotę zapytać się jak można przekonwertować liczbę na "vice versa" ;)
@ŁF - poprawione
poprawcie apostrofy przy stringach