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 -