こんな関数を使ってみてください。もうそのまんまです(笑)
チェックしたい文字列を引数に渡して、それが浮動小数点値だったらTrue、そうでなければFalseを返す関数です。
function
CheckFloat(Value: String): Boolean; var i: Integer; float_mark: Boolean; float_dot : Boolean; begin Result:= False; if Value = '' then Exit; // 文字列が空なら終了 float_mark:= False; float_dot:= False; for i:= 1 to Length(Value) do begin if i = 1 then begin //1文字目をチェック if not (Value[i] = '+') and not (Value[i] = '-') and not (Value[i] = '1') and not (Value[i] = '2') and not (Value[i] = '3') and not (Value[i] = '4') and not (Value[i] = '5') and not (Value[i] = '6') and not (Value[i] = '7') and not (Value[i] = '8') and not (Value[i] = '9') and not (Value[i] = '0') and not (Value[i] = '$') and not (Value[i] = '#') then begin Exit; end; end else begin //2文字目以降をチェック if Value[i] = '.' then begin if float_dot then begin Exit; end else begin float_dot:= True; Continue; end; end; if Value[i] = 'e' then begin if float_mark then begin Exit; end else begin float_mark:= True; Continue; end; end; if not (Value[i] = '1') and not (Value[i] = '2') and not (Value[i] = '3') and not (Value[i] = '4') and not (Value[i] = '5') and not (Value[i] = '6') and not (Value[i] = '7') and not (Value[i] = '8') and not (Value[i] = '9') and not (Value[i] = '0') then begin Exit; end; end; end; Result:= True; end; |
上の場合、判断する要素が文字型で256個以内なので、次のようにするともっと効率的です。
function
CheckFloat(Value: String): Boolean; var i: Integer; float_mark: Boolean; float_dot : Boolean; begin Result:= False; if Value = '' then Exit; // 文字列が空なら終了 float_mark:= False; float_dot:= False; for i:= 1 to Length(Value) do begin if i = 1 then begin //1文字目をチェック if not (Value[i] in ['+', '-', '0'..'9', '$', '#']) then Exit; end else begin //2文字目以降をチェック if Value[i] = '.' then begin if float_dot then begin Exit; end else begin float_dot:= True; Continue; end; end; if CompareText(Value[i], 'e') = 0 then begin if float_mark then begin Exit; end else begin float_mark:= True; Continue; end; end; if not (Value[i] in ['0'..'9']) then Exit; end; end; Result:= True; end; |
あと、FloatToStr() を try... except...
で囲ってチェックするのも手かと思います。
(実際、そっちの方が速いか?)
もっと効率のいい方法があったら教えてください。
浮動小数点のときの応用です。こちらはもっと簡単。
function
CheckInteger(Value: String): Boolean; var i: Integer; begin Result:= False; if Value = '' then Exit; for i:= 1 to Length(Value) do begin if i = 1 then begin if not (Value[i] in ['+', '-', '0'..'9']) then Exit; end else begin if not (Value[i] in ['0'..'9']) then Exit; end; end; Result:= True; end; |
これも、IntToStr() を try... except... で囲ってチェックする手もあるし、IntToStrDef() でデフォルト値をチェックするという方法もあるでしょう。
こんなの、どう?
function
ZeroSupress(Value: String): String; var sBuf: String; L : Integer; i : Integer; begin { 文字列長取得 } L:= Length(Str); { "0"を削る } sBuf:= ''; for i:= 1 to L do if (Str[i] <> '0') and (Str[i] <> #0) then sBuf:= sBuf + Str[i]; Result:= sBuf; end; |
Str[i] <> '0' のところの '0' を他の条件にすることで、ゼロ以外の文字列も削れますな。
もしかすると、VCLに標準でこういうのがあるかもしれませんが。
この例は、Derimiter で各フィールドが区切られた文字列 Src を分析して、各フィールドの文字列を Values に格納しています。Values はあらかじめインスタンスを作っておく必要があります。ここではフィールド数を復帰するようになってますが、これは、Values.Count を見ることでも分かります。
function
ReadDelimiterText(const Src: String; Delimiter: Char; var Values: TStringList): Integer; var i : Integer; src_len : Integer; val_cnt : Integer; str_buf : String; begin { 復帰を0で初期化 } Result:= 0; { 文字列チェック } if Src = '' then Exit; { デリミタチェック } if Delimiter = '' then Exit; { 読込行数リセット } val_cnt:= 0; { 文字列長取得 } src_len:= Length(Src); { バッファリセット } str_buf:= ''; { 区切り解析 } for i:= 1 to src_len do begin if Src[i] = Delimiter then begin Values.Add(str_buf); str_buf:= ''; Inc(val_cnt); end else begin str_buf:= str_buf + Src[i]; end; end; { 最後の文字列を追加 } Values.Add(str_buf); { 読込値数を返す } Result:= val_cnt + 1; end; |
Delphi6なら TStringList の新しいプロパティ DelimitedText を使って次のようにもできます。
function
ReadDelimiterText(const Src: String; Delimiter: Char; var Values: TStringList): Integer; begin { 復帰を0で初期化 } Result:= 0; { 文字列チェック } if Src = '' then Exit; { デリミタチェック } if Delimiter = '' then Exit; { デリミタを設定 } Values.Delimiter:= Delimiter; { 区切り文字列に引数の文字列をセット } Values.DelimitedText:= Src; { 行数を返す } Result:= Values.Count; end; |
Delphi5以前のバージョンにも CommaText というのがあって、これはデリミタがコンマ","に限られますが、同様のことができると思います。
TStringList の代わりに TStringField を使うと、さらに便利になるかも?
[ Delphi へ戻る ]