8.3.2. Преобразование строк
8.3.2.1. Процедура Str( X [: Width [: dec ] ]; VAR S : String)
служит для преобразования числовых значений в строковые. Это, в частности, необходимо для работы с процедурами модуля Graph OutText и OutTextXY. X может быть переменной или значением целого или вещественного типов. Можно задавать поля формата, указывая ширину поля для числа и число знаков после десятичной
- 159 -
точки. Для целых значений можно задать только поле Width, для вещественных — либо оба поля (формат с фиксированной точкой), либо одно — Width. В последнем случае задается экспоненциальный формат общей длиной Width. Напомним, что экспоненциальный формат чувствителен к использованию сопроцессора. Так, для поля Width, равного 13, будем иметь
в режиме {$N-}: -1.234567E+10,
в режиме {$N+}: -1.2346Е+0010.
Если число имеет меньше знаков, чем дано в поле, то оно будет выровнено по правому краю, пустое место заполнится пробелами. Можно задать поле Width отрицательным, в этом случае выравнивание происходит по левому краю, а излишки как бы стираются:
Str(6.66 : 8 : 2, S); { S=' 6.66' }
Str(6.66 : -8 : 2, S); { S='6.66' }
Str(6.66 : 8 : 0, S); { S=' 7' }
Можно задать значения полей формата целочисленными переменными или константами:
VAR
F, n : Integer;
S : String;
...
F:=-5; n:=1;
Str( -123.456 : F : n, S);
Возможность задания поля константой решает проблему экспоненциального формата для случаев использования математического сопроцессора. Достаточно применить команды условной компиляции:
{$IFOPT N+}
CONST FORMAT_E =14; { формат: +n.nnnnnE+NNNN }
{$ELSE}
CONST FORMAT_E =12; { формат: +n.nnnnnE+NN }
{$ENDIF}
...
Str(x : FORMAT_E, S);
Теперь формат будет устанавливаться при компиляции в зависимости от режима использования сопроцессора.
Последнее замечание: если формат с точкой ограничивает число знаков в дробной части, то она будет округлена при преобразовании:
Str(1.234567:6:4, S); {S='1.2346'}
Само значение числа при этом не изменится.
- 160 -
8.3.2.2. Процедура Val(S : String; VAR V; VAR ErrCode : Integer) преобразует числовые значения, записанные в строке S в числовую переменную V. Если преобразование возможно, то переменная ErrCode равна нулю, в противном случае она содержит номер символа в S, на котором процедура застопорилась. Тип V должен соответствовать содержимому строки S. Если в S имеется точка или степень числа Е+nn, то V должна быть вещественного типа, в остальных случаях может быть и целой. Массу сложностей доставляют проблемы переполнения: если S='60000', a V в вызове процедуры будет подставлена типа Byte, то что получится в итоге?
Возможны два варианта. Первый — при работе программы проверяются диапазоны и индексы (режим $R+); при переполнении возникнет фатальная ошибка счета, и программа прервется. Второй — проверка отключена (режим $R-); все зависит от типа V: если он вещественный или LongInt, то при переполнении ErrCode<>0, a V содержит числовой «мусор». Но если V имеет тип «короче» чем LongInt, то ErrCode при переполнении молчит (равно 0), а в V записывается результат переполнения, мало похожий на содержимое S. Не слишком «прозрачно», не так ли? В техническом описании языка после изложения всего этого дается совет, как обойти все эти условности. При преобразовании строк с целыми числами рекомендуется на место V подставлять переменную типа LongInt. Пусть надо перевести строку S с целым значением в переменную WordV типа Word. Схема будет такой:
{$r-}
VAR LongV : LongInt; WordV : Word;
…
WordV := 0; { начальная очистка WordV }
Val( S, LongV, ErrCode }; { вызов преобразования }
if ErrCode=0
then begin { в S записано число }
if ( LongV >= 0 ) and ( LongV <= 65535 )
then { Все в порядке! }
WordV := LongV
else { Иначе несовместимость! }
WriteLn('Ошибка диапазона при преобразовании ',LongV );
end {then}
else { содержимое S не годится }
WriteLn('Ошибка в строке ',S,' в символе ',S[ErrCode]);
При преобразовании строк в другие целые типы достаточно лишь менять диапазон разрешенных значений в операторе IF.
- 161 -