Delphi Tips
>> Index
● 03/04 自作アプリにスペルチェックの機能をつけたい
● 03/04 正規表現の使える検索・置換えライブラリ
● 08/22 プロパティ値を文字列に変換/逆変換
● 05/17 HTMLタグ表記の大文字・小文字変換を行う
● 05/17 文字列から括弧の中のみを削除する
● 05/17 列挙型(Enum)の値と文字列との変換
● 05/17 文字列や画像データをリソースに埋め込むためのコンポーネント
● 12/27 VBのMIDステートメント
● 06/02 トークンの切り出し
● 09/16 Pascal で文字列を効率良く扱う(例:文字列を逆順にする)。
● 09/15 漢数字で位取り表示
● 09/09 文字列を TDateTime に変換する
● 08/13 TColor 値を文字列に変換する
● 05/14 文字数のカウント方法
● 05/08 改行コードの違いについて
● 02/11 和暦を西暦に直したい
● 02/08 Delphi3 の TStringList.CommaText の不具合
● 02/08 文字列の切り分け
最終更新: 7569 日前
0046 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.2 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2004/03/04 osamu 編集
自作アプリにスペルチェックの機能をつけたい
Spell Checker(辞書付き)というコンポーネントが、http://www.cs.monash.edu.au/~vtran/にあります。
Delphian World MLの過去ログにこれに関する話題があるそうです。
http://www.delphianworld.com/
参照: [Delphi-ML:19276] <PASCAL>
0119 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.2 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2004/03/04 osamu 編集
正規表現の使える検索・置換えライブラリ
正規表現を使った文字列探索/操作 : Rexp016.lzh
Perl 互換正規表現ユニット : BRegExp.lzh
DLは Delphian World で、
http://www.delphianworld.com/direct.html?id=MI0036
それか、この手のDLLがいろいろありますからそれらを使うという手がラクだと思います。
VWXW.DLL(Wz Editorで使われている)
作者のM.Ishidaさんのページ
http://www2h.meshnet.or.jp/~ishida/
jre.dll(秀丸エディタで使われている)
http://www.yamada-labs.com/software/spec/jre/
basp21.dll
http://www.hi-ho.ne.jp/babaq/
参照: [Delphi-ML:22272] <PASCAL>
0346 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2003/08/22 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2003/08/22 osamu 編集
プロパティ値を文字列に変換/逆変換
published なプロパティを Ini に書き込みたい・から読み出したいというような時、プロパティ値を文字列に変換する必要が生じます。
Font プロパティを Ini/Registry に保存したい という投稿はFAQに近いですが、この記事はそういった要望への回答となります。
Enum/Set だけではなく、TColor のように「Enum ではないけど文字で書きこまれることがあるプロパティ」にも対応しています。
uses Classes, TypInfo;
function PropertyToString(obj: TPersistent; PropName: string): string;
var IntToIdent: TIntToIdent;
Ident: string;
begin
Result:= GetPropValue(obj, PropName);
if PropType(obj, PropName)=tkInteger then begin
IntToIdent := FindIntToIdent(GetPropInfo(obj, PropName).PropType^);
if Assigned(IntToIdent) then
IntToIdent(GetPropValue(obj, PropName), Result);
end;
end;
procedure StringToProperty(s: string; obj: TPersistent; PropName);
var IdentToInt: TIdentToInt;
i: Integer;
begin
if PropType(obj, PropName)==tkInteger then begin
IdentToInt:= FindIdentToInt(GetPropInfo(obj, PropName).PropType^);
if Assigned(IdentToInt) and IdentToInt(s, i) then begin
SetPropValue(obj, PropName, i);
end else begin
SetPropValue(obj, PropName, s);
end;
end else begin
SetPropValue(obj, PropName, s);
end;
end;
参照: [Delphi-ML:75958] <PASCAL>
0326 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2002/05/17 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2002/05/17 osamu 編集
HTMLタグ表記の大文字・小文字変換を行う
コードはSJISを仮定します。
HTMLのコメント部分、""などで囲まれたパラメータ部分などは変換しません。
速度を気にするのであれば IsDBCSLeadByte は避けるべきです。自分で文字テーブルを作れば速くなります。ByteType の方は最適化されていたと思います。通常の用途では速度が気になることは無いかもしれませんね。
function ChangeHTMLTagCase(s:string; Lower:Boolean):string;
const
sNormal = 0;
sInComment= 1;
sInBracket= 2;
sInQuote = 3;
sInDQuote = 4;
sAfterEq = 5;
var
p: PChar;
state: Integer;
begin
state:= 0;
Result:= s;
UniqueString(Result);
p:= PChar(Result);
while p^<>#0 do begin
if IsDBCSLeadByte(Ord(p^)) and ((p+1)^<>#0) then begin
Inc(p, 2);
end else begin
case state of
sNormal:
if p^='<' then
if StrLComp(p, '<!--', 4)=0
then state:= sInComment
else state:= sInBracket;
sInComment:
if p^='-' then
if StrLComp(p, '-->', 3)=0 then
state:= sNormal;
sInBracket:
case p^ of
'''': state:= sInQuote;
'"': state:= sInDQuote;
'=': state:= sAfterEq;
'>': state:= sNormal;
'A'..'Z': if Lower then p^:= Chr(Ord(p^)+32);
'a'..'z': if not Lower then p^:= Chr(Ord(p^)-32);
end;
sInQuote:
case p^ of
'''': state:= sInBracket;
end;
sInDQuote:
case p^ of
'"': state:= sInBracket;
end;
sAfterEq:
case p^ of
'''': state:= sInQuote;
'"': state:= sInDQuote;
' ': state:= sInBracket;
'>': state:= sNormal;
end;
end;
Inc(p);
end;
end;
end;
参照: [Delphi-ML:66840] <WWW> <通信> <PASCAL>
0325 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2002/05/17 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2002/05/17 osamu 編集
文字列から括弧の中のみを削除する
特に、全角の括弧と半角の括弧に対応した方法を紹介します。一旦WideStringに直しているところが味噌で、こうすることによってコードの見通しが非常に良くなります。
function DeleteInBracket(s:string):string;
const
ZenAki = $FF08;
ZenToji= $FF09;
HanAki = $0028;
HanToji= $0029;
var
PrevPos,Len,BTimes,i:integer;
ss:WideString;
begin
ss := s;
i := 1; PrevPos := 1;Len := Length(ss);BTimes := 0;
result := '';
while i < Len+1 do begin
case Ord(ss[i]) of
ZenAki,HanAki:begin
Inc(BTimes);
if BTimes = 1 then result := result+Copy(ss,PrevPos,i-PrevPos);
end;
ZenToji,HanToji:begin
Dec(BTimes);
if BTimes = 0 then PrevPos := i+1;
end;
end;
inc(i);
If BTimes < 0 then Break;
end;
if BTimes = 0 then
result := result+Copy(ss,PrevPos,i-PrevPos)
else if BTimes < 0 then begin
ShowMessage('カッコが閉じていません-- ( が足りません' );
result := result+Copy(ss,PrevPos,i-PrevPos);
end else begin
ShowMessage('カッコが閉じていません-- ) が足りません' );
end;
end;
また、こういった文字列処理には正規表現を使うとかなり楽ができます。たとえば、
http://www2.big.or.jp/~osamu/Delphi/MyLibrary.htm
の BRegExp ユニットを使えば、
uses BRegExp;
function RemoveParentheses(text: string): string;
begin
Result:= text;
while brx.Subst('s/(\(|()[^()()]{3,1024}(\)|))//gk', Result) do;
end;
とするだけでできてしまいます。
s/// の k というオプションは、BREGEXP.DLL に固有のもので、正規表現中の SJIS を SJIS として認識してくれるので、2バイト文字にも特殊な処理はいらないです。
参照: [Delphi-ML:66865] <PASCAL>
0324 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2002/05/17 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2002/05/17 osamu 編集
列挙型(Enum)の値と文字列との変換
TBrushStyle や TPenStyle などの値を文字列として取り出したい、またはそのような文字列からもとの値に戻したい場合、TypInfoユニットにあるGetEnumNameやGetEnumValueを使用します。
uses TypInfo;
function AlignmentToString(Value: TAlignment): String;
begin
Result := GetEnumName(TypeInfo(TAlignment),Ord(Value));
end;
こんな感じですね。
参照: [Delphi-ML:66981] <PASCAL>
0320 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2002/05/17 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2002/05/17 osamu 編集
文字列や画像データをリソースに埋め込むためのコンポーネント
プログラム内部で使いたい文字列や画像のデータを、フォーム上に置いた非ビジュアルコンポーネントに保存しておくと、アプリケーションと別にファイルを配布する必要が無くなり、便利な場合があります。
そういった用途に使えるコードが[Delphi-ML:67285]のスレッドに紹介されています。ただし、画像データなどは文字列にエンコードされますので、そのままファイルを持つ場合に比べ、ファイルサイズは大きくなってしまいます。
[Delphi-ML:50664]で中村さんが紹介されたコンポーネントは任意のバイナリデータを内部に持てるようです。
参照: [Delphi-ML:67285] <画像> <PASCAL>
0313 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2001/12/05 濱野 rev 1.5 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2001/12/27 濱野 編集
VBのMIDステートメント
Delphi6でVB互換の関数などが追加されました。
Mid関数もそのひとつですが、部分文字列の挿入
であるMidステートメントはありません。
S = "1234567890"
Mid(S, 3, 5) = "ABC"
そこで逆Mid関数ともいうべきMidステートメントを
シミュレートする手続きを作ってみました。
procedure MidInsert(var S1: String; P, N: Integer; S2: String);
var
L: Integer;
begin
L := Length(S1);
if N > (L - P + 1) then
N := (L - P + 1);
if N > Length(S2) then
N := Length(S2);
Delete(S1, P, N);
Insert(Copy(S2, 1, N), S1, P);
end;
{ テスト例: }
procedure TForm1.Button1Click(Sender: TObject);
var
S: String;
begin
S := '1234567890';
MidInsert(S, 5, 3, 'ABC');
ShowMessage(S);
end;
Delphiの文字列型は配列と同様の扱いも出来るのでDelete, Insert, Copyを
使わない別の方法もあります。一時オブジェクトが作成されない分、
こちらの方が高速に動作するかもしれません。
procedure MidInsert(var S1: String; P, N: Integer; S2: String);
var
L, I: Integer;
begin
L := Length(S1);
if N > (L - P + 1) then
N := (L - P + 1);
if N > Length(S2) then
N := Length(S2);
StrMove(Pchar(@S1[P]), PChar(S2), N);
end;
参照: <PASCAL>
0309 D1D2D3 D4 D5 D6 D7 3.1 95 98 作成: 2001/05/25 濱野 rev 1.6 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2001/06/02 K.Takaoka 編集
トークンの切り出し
Delphiのライブラリにはstrtokのようなトークンの切り出し
を行なう関数や手続きが無い為、自作することになります。
以下のコードはCopyとIsDelimiter関数を使ったトークンの
切り出し例です。
{$APPTYPE CONSOLE}
program Typing;
uses
SysUtils;
procedure TypingToken(S, Delims: String);
var
TokenIn : Boolean; // 進行中であるかのフラグ
TokenS, TokenLen, // トークンの開始位置と長さ
I: Integer;
begin
TokenIn := False;
TokenS := 0;
TokenLen := 0;
for I := 1 to Length(S) do
begin
if not IsDelimiter(Delims, S, I) then begin
if TokenIn then
Inc(TokenLen)
else begin
TokenS := I;
TokenLen := 1;
TokenIn := True
end
end else begin
if TokenIn then begin
Writeln(Copy(S, TokenS, TokenLen));
TokenIn := False;
TokenLen := 0;
end
end
end;
if Tokenlen > 0 then
Writeln(Copy(S, TokenS, TokenLen));
end; { TypingToken }
const
Delims = #9#10#13'[](){};, ';
var
Buf: String;
begin
while not EOF(Input) do begin
Readln(Buf);
TypingToken(Buf, Delims)
end
end.
※リダイレクトしない場合、最後に[Ctrl]+[Z]を入力
して下さい。
参照: <PASCAL>
0234 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/09/04 西坂良幸 rev 1.8 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/16 osamu 編集
Pascal で文字列を効率良く扱う(例:文字列を逆順にする)。
MLの全体がコーディングの勉強ですが、[Delphi-ML:42129] から始まる一連のスレッド「文の逆」は、Pascal で文字列(文)を効率良く扱う様々なコーディングの例が示されています。いろいろな方法があることがわかりますね。勉強になります。
実装で気をつけるのは、2バイト文字と、CR/LF の順を入れ替えないようにしなければならないというところです。
(1) 何も考えないで作る
function StrReverse(s: string): string;
var i: Integer;
LeadBytes: set of Char;
begin
i:= 1;
Result:= '';
LeadBytes:= SysUtils.LeadBytes + [#13];
while i<=Length(s) do begin
if s[i] in LeadBytes then begin
Result:= Copy(s,i,2) + Result;
i:= i+2;
end else begin
Result:= Copy(s,i,1) + Result;
i:= i+1;
end;
end;
end;
この関数が、ループ中で何百回も一度に呼ばれるとは考えにくいので、実はこれで十分かもしれませんが、後学のために工夫の余地を考えてみることにしましょう。
(2) [Delphi-ML:42142] 基本的な形です。(ただし、処理速度を考慮しています。)
function StrReverse(const s: string): string;
var
i, L: integer;
begin
L := Length(s);
SetLength(result, L);
i := 1;
while i <= L do
begin
if (s[i] in SysUtils.LeadBytes) or
((s[i] = #13) and (S[i+1] = #10))
then
begin
result[L-i] := s[i];
result[L-i+1] := s[i+1];
Inc(i, 2);
end
else
begin
result[L-i+1] := s[i];
Inc(i);
end;
end;
end;
コード(1)も同じなんですが、実はこれデータによっては s[Length(s)+1] を参照してしまいます。不正な文字列の場合は無視するにしても、改行を常に #13#10 と仮定して(1)のように比較部分を単純化するか、i=Length(s) のときには s[i+1] を参照しないか、どちらかにしないと意味が無いです。
ま、それは置いといて、、、
文字列の生成回数を減らす(Copy 関数は値を返すのに string を生成する)
文字列の足し算の回数を減らす(足し算も内部で新しい文字列を作る)
関数の呼び出しを最小限にする(Length の値を L にキャッシュ)
i:=i+1 の代わりに Inc 関数を使う(C での ++ 演算子と同等)
引数に const をつける(これも文字列の生成を押さえられる)
などが高速化部分。効果が大きい順に並べてみました。今回の目的には後ろの3つはたいした違いは生みません。特に、Length 関数のコストはそれほど大きくないことは覚えておいても良いと思います。逆に文字列の連結は時間がかかるので注意。
(3) [Delphi-ML:42157] ポインタの使い方の見本のような例ですね。
function StrReverse(const s: string): string;
var
p, pn, pr: PChar;
begin
SetLength(Result, Length(s));
p := PChar(s);
pr := PChar(Result) + Length(s);
while p^ <> #0 do begin
if (p^ = #13) and ((p+1)^ = #10) then
pn := p + 2
else
pn := CharNext(p);
System.Move(p^, (pr-(pn-p))^, pn-p); Dec(pr, pn-p);
p := pn;
end;
end;
コード(2)から、さらに [ ] の使用を無くして高速化を図ったものです。Pascal の [ ] は C の [ ] に比べてかなり時間がかかります。CharNext という関数も覚えていてよさそうですね。でも高々2バイトの転送に System.Move を使うよりは、(2) のように SysUtils.LeadBytes を使って判定して1バイトずつ ^ で転送した方がずっと速いでしょう。
2バイト文字の判断で2バイト目が #0 でないことを確認しないと、不正なデータが与えられた時に、メモリを破壊してシステムをハングアップさせる危険性があります。p_end:=PStr(s)+Length(s); としておいて、while の比較を、p<=p_end とすればハングアップを防ぎつつさらに高速化にもなりますね。
(4) [Delphi-ML:42148] ポイントは再帰ですね。
function StrReverse(const s: string): string;
var
L: integer;
begin
result := '';
L := Length(s);
if L = 0 then
exit;
if IsDBCSLeadByte(Byte(s[1])) then
result := StrReverse(copy(s, 3, L-2)) + s[1] + s[2]
else
result := StrReverse(copy(s, 2, L-1)) + s[1];
end;
コードはすっきりしますが、速度的には(1)よりずっと悪いです。なにより、長〜い文字列を渡すと再帰が深くなりすぎて、スタックオーバーフローを起こしかねないので、この目的には使えません。えっと、この例だけ改行文字を考慮していないですね。
(5) [Delphi-ML:42155] WideStringを使う発想です。
function StrReverse(s: WideString): WideString;
const
WCharCR : WideChar = #$0d;
WCharLF : WideChar = #$0a;
var
i : Integer;
begin
SetLength(Result, Length(s));
for i:=1 to Length(s) do begin
if (s[i] = WCharCR) and (s[i+1] = WCharLF) then begin
s[i] := WCharLF; s[i+1] := WCharCR;
end;
Result[Length(s)-i+1] := s[i];
end;
end;
WideString を使うことで、2バイト文字を考えなくても良くなります。もし、改行文字が含まれないことが分かっていれば、if 文は必要無くなりますから、非常にすっきりしたコードになります。WideString <-> string の変換はキャストの必要無く自動で行われます。変換は時間がかかりますが、初めと終わりの2回だけなので、この場合には気にする必要は無いでしょう。美しいコードです。
(6) [Delphi-ML:42173] 文字列の両端から交換していこうというアイディア
function StrReverse(const s: string): string;
var
len, i : integer;
L, R : pchar;
tmp : char;
p : pchar;
begin
Result := s;
len := length(s); if len = 0 then exit ;
p := PChar(Result);
L := p; R := L + len - 1;
while L < R do
begin
if (L^ in Sysutils.LeadBytes) or
((L^ = #13) and ((L+1)^ = #10)) then
begin
tmp := L^; L^ := (L+1)^; (L+1)^ := tmp;
inc(L, 2);
end
else
inc(L);
end;
L := p; R := L + len - 1;
for i := 1 to (len div 2) do
begin
tmp := L^; L^ := R^; R^ := tmp;
inc(L); Dec(R);
end;
end;
うーん何やら複雑。改行文字や2バイト文字が無くて、なおかつ関数が
procedure StrReverse(var s: string): string;
のように、直接引数を書きかえるものなら、メリットはあるかもしれません。。。この場合には、ほぼ最後の for 文だけになってしまいます。
基本的に、ループの中で何度も繰り返し呼ばれるので無ければ、実行速度を求めて読みにくいコードを書くのは愚とされます。したがって、この問題に限って言えば、(1) や (5) のように分かりやすく書けるものがお勧めです。
ただし、実行効率を考慮しないといっても限度があり、(4) のように、長い文字列を渡すとスタックオーバーフローを起こすようなコードは、いかに見やすくても不適当でしょう。
あなたならどう書きますか? アイデアある方はどんどん加筆して下さい。
参照: [Delphi-ML:42134] <PASCAL>
0261 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/09/15 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/15 osamu 編集
漢数字で位取り表示
数字を漢数字で位取り表示(4桁単位)する関数を作ってみました。
function RhKnjNumber(const Num: Currency): string;
begin
Result := FormatFloat('####"兆"####"億"####"万"####円', Num);
while True do {余計な文字を取り去る}
if ByteType(Result, 1) = mbLeadByte then
Result := Copy(Result, 3, Length(Result) - 2)
else
Break;
end;
参照: [Delphi-ML:34500] <PASCAL>
0250 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/09/09 osamu rev 1.2 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/09 osamu 編集
文字列を TDateTime に変換する
文字通り StrToDateTime という関数もあるんですが、これは yyyy/mm/dd などの形式にしか対応していません。ちょっとひねって VarToDateTime を使えば、ほぼどんな形式でもうまく変換できます。string -> Variant は自動で変換されるので、そのまま文字列を渡すだけで使えます。
MyDateTime := VarToDateTime('平成1年1月1日午後1時1分1秒');
全角数字もOKですが、さすがに '平成九年九月九日' は無理でした。
VarToDateTime('1999/1/2') = VarToDateTime('1/2/1999');
の結果は、True になりました。
注意点として、VerToDateTime は StrToDateTime と違い、ShortDateFormat グローバル変数を見ていないようです。
ShortDateFormat:='DD/MM/YY';
ShowMessage(FloatToStr(VarToDateTime('2/1/1999')-VarToDateTime('平成11年2月1日')));
の結果は 0 になります。
参照: <日時> <PASCAL>
0203 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/08/13 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/08/13 osamu 編集
TColor 値を文字列に変換する
レジストリに TColor 型の値を格納したいような場合、ColorToString 関数を使えば TColor から AnsiString に変換できるので、あとは TRegistry の WriteString で書き出してやればいいと思います。
反対に AnsiString から TColor に戻すのは StringToColor 関数を使えばいいです。
詳しくはヘルプを見てください。
参照: [builder:17839] <PASCAL> <描画>
0186 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/05/14 おばQ rev 1.2 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/05/14 おばQ 編集
文字数のカウント方法
普通にLength関数で文字数をカウントすると半角文字の数になります。例えばLength('あいうえおABCDE')は15です。
全角文字を1文字としてカウントするにはWideStringを使います。Length(WideString('あいうえおABCDE'))は10です。
WideStringにキャストするより高速な手法としてByteToCharLenを使う方法もあります。
ByteToCharLen('あいうえおABCDE', Length('あいうえおABCDE'))は10です。
参照: <PASCAL>
0181 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/05/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/05/08 osamu 編集
改行コードの違いについて
テキストを扱っていると、何かと改行コードについて気になります。
改行コードは Windows では CRLF、Macでは CR のみ、Unix 系では LF のみで示されます。制御コードとして CR が復帰 LF が改行と呼ばれます。Delphiでは CR=Char(13) または #13、LF=Char(10) または #10 として指定できます。
Label 等ではテキストの改行を行う場合、CRLF, CRのみ, LFのみ、どの場合でも改行が行えますので
Label.caption := '1行目'#10'2行目'という表現も可能です。
また、改行コードが、CR のみ、LF のみ、LFCR になっているテキストを CRLF シーケンス(つまりWindows標準形式)に変換する関数としてAdjustLineBreaks というものがあります。逆に CRLF から、CR のみLF のみ、に変換するには
function DeleteCR(S: string): string;
begin
while pos(#13,S)<>0 do
Delete(S,pos(#13,S),1);
Result := S;
end;
このようなものを使ってください。DeleteLFも作れるでしょう
(D4以降ではStringReplace関数が用意されていますのでそちらを使いましょう)
参照: [Delphi-ML:9035] <PASCAL>
0151 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/11 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/11 osamu 編集
和暦を西暦に直したい
こんなのはどうでしょう?
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key<>#13 then
Exit;
Key:= #0;
with Edit1 do
try
Text:= FormatDateTime('yyyy/m/d',VarToDateTime(Text));
SelectAll;
except
on EVariantError do begin
SelectAll;
raise Exception.Create('入力が不正です');
end;
end;
end;
98/8/21 h10/8/21 s24-10-2 m1/1/1 8/21 8/21/98 98/5 1996-8/21
等 ほとんど何でもありです。半角、全角関係なしです。
参照: [Delphi-ML:25313] [Delphi-ML:25315] <計算> <日時> <PASCAL>
0033 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
Delphi3 の TStringList.CommaText の不具合
個々のアイテムが空白などを含む場合にのみダブルクオートで括るはずが、必要の無いときまでダブルクオートが使われる。
[対応策]
class.pas の 2253 行目から4行だけ示します。"" で包む必要があるなら
包む処理をする部分です。
S := Get(I);
P := PChar(S);
while not (P^ in [#0..' ','"',',']) do P := CharNext(P);
if (P <> #0) then S := AnsiQuotedStr(S, '"');
// ^^ ここ正しくは P^ 。
// ポインタと文字を比べるんじゃなーい!!
参照: [Delphi-ML:8468] <バグ> <PASCAL>
0022 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
文字列の切り分け
>> 以下のような文字列dumStringにおいて、その中に含まれている引数term3だけを得たい。
>>
>> dumString := 'program term1 term2 term3 term4 term5';
GetTokenIndex(dumString,' ',4)でterm3を返します。
{---------------------------------------------------------------------}
function RemoveToken(var s:string;delimiter:string):string;
var p:Integer;
begin
p:=Pos(delimiter,s);
if p=0 then Result:=s
else Result:=Copy(s,1,p-1);
s:=Copy(s,Length(Result)+Length(delimiter)+1,Length(s));
end;
{---------------------------------------------------------------------}
function GetTokenIndex(s:string;delimiter:string;index:Integer):string;
var i:Integer;
begin
Result:='';
for i:=0 to index do
Result:=RemoveToken(s,delimiter);
end;
{---------------------------------------------------------------------}
RemoveTokenはsをdelimiterで切り分けたときの一番始めの部分を返し、sから取り除きます。sにdelimiterが含まれないときにはs全体を返し、sは空文字列になります。
GetTokenIndexは、sをdelimiterで切り分けたときのindex番目の部分を返します。一番始めの部分はindex=0です。sは変更されません。
indexが範囲外の場合には空文字列が返ります。
delimiterはstring型になっているので、#13#10や' : 'などで切り分けるのもOKです。
参照: [Delphi-ML:12110] <PASCAL>
[新規作成] [最新の情報に更新]
How To
Lounge
KeyWords
Osamu Takeuchi osamu@big.or.jp
Tips
Delphi
Home