プログラム構造と基本
プログラム構造とユニット
Delphiプログラムは'program'で始まり、'end.'(ピリオド付き)で終わる。{$APPTYPE CONSOLE}はコンパイラ指令でコンソールアプリとしてマークする。'uses'はユニット(モジュール)をインポート — System.SysUtilsにはFormat、IntToStrなどがある。ユニットにはinterface部(公開宣言)とimplementation部(コード)がある。WriteLnは改行付きでテキストを出力、Writeは改行なし。ReadLnは入力を読み取る(または一時停止)。メインのbegin..endブロックがプログラムのエントリポイント。
program Demo; // program keyword starts a console app
{$APPTYPE CONSOLE} // compiler directive: console application
uses // import units (like #include or import)
System.SysUtils, // utilities (Format, IntToStr, etc.)
System.Classes; // TList, TStrings, etc.
// a unit has interface (declarations) and implementation (bodies)
// unit Math;
// interface
// function Add(A, B: Integer): Integer;
// implementation
// function Add(A, B: Integer): Integer;
// begin Result := A + B; end;
// end.
var
Name: string;
begin
Name := 'Alice';
WriteLn('Hello, ', Name, '!'); // WriteLn = output with newline
Write('No newline'); // Write = output without newline
ReadLn; // wait for Enter (pause)
end.変数、型と定数
Delphiは強く型付けされる。一般的な型:Integer(32ビット)、Int64(64ビット)、Double(64ビット浮動小数点)、Extended(x86では80ビット浮動小数点)、Single(32ビット浮動小数点)、string(Unicode、参照カウント付き)、Char(WideChar、2バイト)、Boolean、Byte(0-255)。TDateTimeは実際にはDouble(1899-12-30からの日数)。定数は'const'を使用 — 型付き定数は型を持ち、型なしは柔軟。部分範囲型(0..150)は値を制限。列挙型(TDay)は名前付き定数を定義。Format()はsprintfのようなもの:%s(文字列)、%d(整数)、%f(浮動小数点)。
var
Name: string = 'Alice'; // string (managed, reference-counted)
Age: Integer = 30; // 32-bit signed integer
BigNum: Int64 = 9223372036854775807; // 64-bit
Pi: Double = 3.14159; // 64-bit float (IEEE 754)
E: Extended = 2.71828; // 80-bit float (x87)
Rate: Single = 0.5; // 32-bit float
Ch: Char = 'A'; // 2-byte Unicode char (WideChar)
IsDev: Boolean = True; // True/False
Bytes: Byte = 255; // 0..255
Date: TDateTime; // date/time (double)
// constants
const
MaxRetries = 3; // untyped constant
Pi: Double = 3.14159265; // typed constant
Greeting: string = 'Hello';
// type aliases
type
TAge = 0..150; // subrange type
TDay = (Mon, Tue, Wed, Thu, Fri, Sat, Sun); // enumeration
begin
Date := Now; // current date/time
WriteLn(Format('%s is %d', [Name, Age])); // formatted output
WriteLn('Pi = ', Pi:0:2); // 3.14 (width:decimals)
end;演算子と式
Delphiは代入に:=を使用し、等価に=を使用する(C系言語の逆)。divは整数除算、/は実数除算(常にExtended/Doubleを返す)。modは剰余。and/or/not/xorはBoolean(論理)と整数(ビット単位)の両方で動作 — 文脈で決まる。shl/shrはビットシフト。Inc/Decは効率的なインプレメント増減分(A := A + 1と書かない)。文字列連結には+を使用。Power()はSystem.Mathにある。:=と=の区別は初心者のエラーの最大の原因。
var
A, B: Integer;
X, Y: Double;
S1, S2: string;
begin
A := 10; B := 3;
WriteLn(A + B); // 13 (addition)
WriteLn(A - B); // 7
WriteLn(A * B); // 30
WriteLn(A div B); // 3 (integer division)
WriteLn(A mod B); // 1 (remainder)
WriteLn(A / B); // 3.33 (real division, always Extended)
X := 2.0; Y := 3.0;
WriteLn(X + Y); // 5.0
WriteLn(Power(X, Y)); // 8.0 (needs System.Math)
// comparison (return Boolean)
WriteLn(A > B); // TRUE
WriteLn(A = B); // FALSE (= is equality, not assignment!)
WriteLn(A <> B); // TRUE (not equal)
WriteLn(A >= B); // TRUE
// logical operators
WriteLn(True and False); // FALSE
WriteLn(True or False); // TRUE
WriteLn(not True); // FALSE
WriteLn(True xor False); // TRUE
// string concatenation
S1 := 'Hello'; S2 := 'World';
WriteLn(S1 + ', ' + S2 + '!'); // Hello, World!
// bitwise (on integers)
WriteLn(5 and 3); // 1
WriteLn(5 or 3); // 7
WriteLn(5 shl 1); // 10 (shift left = *2)
WriteLn(5 shr 1); // 2 (shift right = /2)
// Inc and Dec (modify in place)
Inc(A); // A := A + 1
Inc(A, 5); // A := A + 5
Dec(A); // A := A - 1
end;入出力とフォーマット
Format()はDelphiのsprintf — %s(文字列)、%d(整数)、%f(浮動小数点)、%x(16進数)、%m(通貨)を使用し、幅/精度修飾子付き。WriteLn(value:width:decimals)は浮動小数点を直接フォーマット。ReadLnは入力を変数に読み取る。StrToInt/StrToFloatは文字列を数値に変換(失敗時にEConvertErrorをスロー)、TryStrToIntはBooleanを返し安全。IntToStr/FloatToStrは数値を文字列に変換。FormatDateTimeは日付をフォーマット(yyyy、mm、dd、hh、nn、ss)。FloatToStrFは精密な制御を提供(ffFixed、ffCurrency、ffExponent)。
var
Name: string;
Age: Integer;
Salary: Double;
begin
// console output
WriteLn('Hello, World!'); // with newline
Write('No newline'); // without
WriteLn; // just a newline
// formatted output with Format (like sprintf)
WriteLn(Format('Name: %s, Age: %d', ['Alice', 30]));
WriteLn(Format('Pi: %.4f', [3.14159])); // Pi: 3.1416
WriteLn(Format('Hex: %x', [255])); // Hex: FF
WriteLn(Format('Pad: %10d', [42])); // right-aligned
WriteLn(Format('Left: %-10d|', [42])); // left-aligned
WriteLn(Format('Money: %m', [1234.56])); // currency
// WriteLn with format specifiers (width:decimals)
WriteLn(3.14159:0:2); // 3.14
WriteLn(42:5); // 42 (width 5)
// console input
Write('Enter your name: ');
ReadLn(Name);
Write('Enter your age: ');
ReadLn(Age);
// type conversion functions
Salary := StrToFloat('50000.50');
Age := StrToInt('30');
WriteLn(IntToStr(42)); // '42'
WriteLn(FloatToStr(3.14)); // '3.14'
WriteLn(FloatToStrF(3.14159, ffFixed, 8, 2)); // '3.14'
WriteLn(FormatDateTime('yyyy-mm-dd', Now)); // '2024-06-18'
// TryStrToInt (safe parsing)
if TryStrToInt('123', Age) then
WriteLn('Parsed: ', Age);
end;ユニット、スコープと可視性
ユニットはDelphiのモジュール。interface部は公開内容(ユーザーに見える)を宣言、implementation部はコードを含みプライベートな型/変数を持てる。initialization/finalization部はユニットのロード/アンロード時に実行(ユニットのコンストラクタ/デストラクタのようなもの)。interfaceで宣言された変数はグローバル、implementationではユニットプライベート。interface部の型は公開、implementation部ではプライベート。この2部構成によりユニットレベルでカプセル化を強制。'uses'節は他のユニットをインポート — UnitName.Identifierで名前の衝突を解決。
// Unit declaration
unit MathHelper;
interface
uses
System.SysUtils;
// public types (visible to users of the unit)
type
TCalculator = class
public
function Add(A, B: Integer): Integer;
end;
// public constants
const
Pi = 3.14159265358979;
// public variables
var
Counter: Integer;
// public function declarations
function Multiply(A, B: Integer): Integer;
implementation
// private types (only visible inside this unit's implementation)
type
TInternal = record
Value: Integer;
end;
// private variables
var
InternalCount: Integer;
// function body (implementation)
function Multiply(A, B: Integer): Integer;
begin
Result := A * B;
end;
function TCalculator.Add(A, B: Integer): Integer;
begin
Result := A + B;
end;
initialization
// runs when the unit loads
Counter := 0;
InternalCount := 0;
finalization
// runs when the unit unloads (cleanup)
// free resources here
end.制御フロー
If...Then...Else
If...Then...ElseはDelphiの条件分岐。重要:'else'の前にセミコロンなし — セミコロンは文を終了し、elseはifの一部。複数文の分岐にはbegin..endで囲む(それでもelseの前にセミコロンなし)。and/or/notは論理演算子(整数ではビット単位でも)。括弧で条件をグループ化:(A > 0) and (B > 0)。else前のセミコロン忘れは初心者に最も多いDelphi構文エラー。
var
Score: Integer;
Grade: string;
begin
Score := 85;
// simple if
if Score >= 60 then
WriteLn('Pass');
// if-else (no semicolon before 'else'!)
if Score >= 90 then
Grade := 'A'
else if Score >= 80 then
Grade := 'B'
else if Score >= 70 then
Grade := 'C'
else
Grade := 'F';
WriteLn('Grade: ', Grade);
// multi-statement if (needs begin..end)
if Score > 50 then
begin
WriteLn('Passed');
WriteLn('Congratulations');
end
else
begin
WriteLn('Failed');
WriteLn('Try again');
end;
// nested with logical operators
if (Score >= 0) and (Score <= 100) then
WriteLn('Valid score');
end;Case(Switch)文
CaseはDelphiのswitch — 順序型(Integer、Char、列挙型、部分範囲)で動作。各分岐は単一値、カンマ区切りリスト('D', 'F')、または範囲(1..5)。else節がデフォルト。Caseはフォールスルーしない(Cと異なる)。複数文の分岐にはbegin..endを使用。離散値にはif-elseの連鎖よりCaseがクリーン。文字列には直接caseできない(if-elseまたはルックアップを使用)。
var
Grade: Char;
Day: Integer;
begin
Grade := 'B';
// case on ordinal (integer, char, enum)
case Grade of
'A': WriteLn('Excellent');
'B': WriteLn('Good');
'C': WriteLn('Average');
'D', 'F': WriteLn('Poor'); // multiple values
else
WriteLn('Invalid grade'); // default (else clause)
end;
// case with ranges
Day := 3;
case Day of
1..5: WriteLn('Weekday'); // range
6, 7: WriteLn('Weekend');
else
WriteLn('Invalid day');
end;
// case with enums
type TColor = (Red, Green, Blue);
var C: TColor;
C := Green;
case C of
Red: WriteLn('Stop');
Green: WriteLn('Go');
Blue: WriteLn('Relax');
end;
// case with multi-statement branches
case Grade of
'A': begin
WriteLn('Excellent');
WriteLn('Keep it up');
end;
'B': WriteLn('Good');
end;
end;Forループ(To、Downto、In)
For...toは昇順、For...downtoは降順で反復。ループ変数はループ内で変更不可。For...in(モダンDelphi)は配列、文字列(文字ごと)、セット、任意の列挙可能なものを反復。Breakはループを脱出、Continueは次の反復へスキップ。組み込みのステップはない — 条件またはwhileループを使用。ループ変数はループ後に未定義(値に依存しない)。コレクションにはFor...inが推奨(クリーン、インデックスエラーなし)。
var
i: Integer;
Fruits: array of string;
S: string;
begin
// for...to (ascending)
for i := 1 to 5 do
WriteLn(i); // 1 2 3 4 5
// for...downto (descending)
for i := 5 downto 1 do
WriteLn(i); // 5 4 3 2 1
// for with step (no built-in step — use a while or compute)
for i := 0 to 9 do
if i mod 2 = 0 then
WriteLn(i); // 0 2 4 6 8
// nested loops
for i := 1 to 3 do
for j := 1 to 3 do
Write(i * j, ' ');
WriteLn;
// for...in (iterates collections, modern Delphi)
Fruits := ['apple', 'banana', 'cherry'];
for S in Fruits do
WriteLn(S);
// for...in on string (iterates characters)
for S in 'Hello' do
Write(S, ' '); // H e l l o
WriteLn;
// for...in on set
type TDigits = set of 1..5;
var D: TDigits := [1, 3, 5];
for i in D do
WriteLn(i); // 1 3 5
// Break and Continue
for i := 1 to 100 do
begin
if i > 10 then Break; // exit loop
if i mod 2 = 0 then Continue; // skip to next iteration
WriteLn(i); // 1 3 5 7 9
end;
end;WhileとRepeat...Until
Whileは本体の前にテスト(実行されない可能性あり)、repeat...untilは後にテスト(常に少なくとも1回実行)。重要:whileは条件がTRUEの間継続、repeatは条件がTRUEになったら停止(逆のロジック!)。repeat...untilはbegin..end不要(本質的にブロック)。'ゼロ回以上'にはwhile、'1回以上'にはrepeatを使用。Breakは脱出、Continueはテストへスキップ。while True with Breakは複雑な終了条件を持つループの一般的なイディオム。
var
Count: Integer;
Line: string;
begin
// while: test BEFORE (may never run)
Count := 0;
while Count < 3 do
begin
WriteLn(Count);
Inc(Count);
end;
// 0 1 2
// repeat...until: test AFTER (runs at least once)
Count := 0;
repeat
WriteLn(Count);
Inc(Count);
until Count >= 3;
// 0 1 2
// KEY DIFFERENCE: while continues while TRUE; until stops when TRUE
// while X < 3 do ... == repeat ... until X >= 3
// repeat doesn't need begin..end (it's already a block)
Count := 5;
repeat
WriteLn(Count);
Dec(Count);
until Count = 0;
// reading input until a condition
repeat
Write('Enter "quit" to stop: ');
ReadLn(Line);
until (Line = 'quit') or (Line = 'exit');
// infinite loop with Break
while True do
begin
WriteLn('Running...');
if SomeCondition then Break;
end;
// Continue in while
Count := 0;
while Count < 10 do
begin
Inc(Count);
if Count mod 2 = 0 then Continue;
WriteLn(Count); // 1 3 5 7 9
end;
end;With...DoとGoto
With...Doはレコード/オブジェクトのメンバーに変数を繰り返さずにアクセス — 初期化と冗長性削減に便利。ネストしたWithは避ける(メンバーがどのオブジェクトに属するか曖昧)。Gotoはラベルにジャンプ — モダンDelphiでは稀(Break/Continue/Exitを推奨)、'label'でラベルを宣言。Exitはプロシージャを即座に離脱、Exit(value)は関数から値を返す(モダン構文)。Withは過剰に使用するとコードが読みにくくなる — 単純なケースに控えめに使用。
type
TPerson = record
Name: string;
Age: Integer;
Email: string;
end;
var
P: TPerson;
i: Integer;
label
RetryPoint; // declare a label for Goto
begin
// With...Do: access record/object members without repeating the name
with P do
begin
Name := 'Alice';
Age := 30;
Email := '[email protected]';
WriteLn(Name, ' is ', Age); // instead of P.Name, P.Age
end;
// With on a function result
with TStringList.Create do
try
Add('line 1');
Add('line 2');
SaveToFile('output.txt');
finally
Free;
end;
// nested With (avoid — ambiguous)
with P, TStringList.Create do
try
Add(Name); // Name could be P.Name or TStringList.Name
finally
Free;
end;
// Goto (rarely used — prefer structured alternatives)
i := 0;
RetryPoint:
Inc(i);
WriteLn('Attempt ', i);
if i < 3 then
Goto RetryPoint;
WriteLn('Done after ', i, ' attempts');
// Exit: leave the current procedure/function
if P.Age < 0 then
begin
WriteLn('Invalid age');
Exit; // return immediately
end;
// Exit with a value (for functions)
// Exit(42); // returns 42 from the function
end;文字列とテキスト処理
文字列型と操作
Delphiのデフォルト文字列はUnicodeString(UTF-16、参照カウント付き、コピーオンライト)。文字列は1インデックス(S[1]が最初の文字)— Cプログラマのバグの一般的な原因。Length()は文字数を返す。Pos()は部分文字列を検索(見つからない場合は0を返す、-1ではない)。Copy()は部分文字列を抽出(Start、Count)。StringReplaceは置換(rfReplaceAllですべての出現)。Trim/TrimLeft/TrimRightは空白を削除。Split/Joinはモダンメソッド(TArray<string>)。大文字小文字を区別しない比較にはSameTextを使用。
var
S: string; // UnicodeString (default, UTF-16, reference-counted)
A: AnsiString; // 8-bit string (legacy, codepage-aware)
W: WideString; // COM-compatible (not reference-counted)
SB: StringBuilder; // mutable, for heavy concatenation
begin
S := 'Hello, World';
// length and indexing (1-indexed!)
WriteLn(Length(S)); // 12
WriteLn(S[1]); // 'H' (first char — 1-indexed!)
WriteLn(S[Length(S)]); // 'd' (last char)
// case conversion
WriteLn(UpperCase(S)); // HELLO, WORLD
WriteLn(LowerCase(S)); // hello, world
// searching
WriteLn(Pos('World', S)); // 8 (1-indexed position, 0 if not found)
WriteLn(Pos('xyz', S)); // 0
// substring
WriteLn(Copy(S, 1, 5)); // 'Hello' (Start, Length)
WriteLn(Copy(S, 8, 5)); // 'World'
// modify (creates new string — strings are immutable-ish)
S := StringReplace(S, 'World', 'Delphi', [rfReplaceAll]);
WriteLn(S); // Hello, Delphi
// trim
WriteLn(Trim(' hi ')); // 'hi'
WriteLn(TrimLeft(' hi ')); // 'hi '
WriteLn(TrimRight(' hi ')); // ' hi'
// split
var Parts: TArray<string>;
Parts := 'a,b,c'.Split([',']);
WriteLn(Length(Parts)); // 3
// join
WriteLn(string.Join('-', Parts)); // 'a-b-c'
// comparison
WriteLn('abc' = 'abc'); // TRUE (case-sensitive)
WriteLn(AnsiCompareText('ABC', 'abc')); // 0 (case-insensitive)
WriteLn(SameText('ABC', 'abc')); // TRUE
end;文字列フォーマットと変換
Format()はDelphiのsprintf:%d(整数)、%f(浮動小数点)、%s(文字列)、%x(16進数)、%m(通貨)、幅/精度修飾子付き。FloatToStrFは精密な制御を提供(ffFixed、ffCurrency、ffNumber、ffExponent)。FormatDateTimeは日付をフォーマット:yyyy(4桁年)、mm(月)、dd(日)、hh(時)、nn(分)、ss(秒)、dddd(完全な曜日名)、mmmm(完全な月名)。StrToInt/StrToFloatは無効な入力でEConvertErrorをスロー、TryStrToIntはBooleanを返す(安全)。ユーザー入力には常にTry...を使用。
var
N: Integer := 42;
F: Double := 3.14159;
S: string;
D: TDateTime := Now;
begin
// Format (like sprintf)
S := Format('Integer: %d', [N]); // 'Integer: 42'
S := Format('Float: %f', [F]); // 'Float: 3.14'
S := Format('Float: %.4f', [F]); // 'Float: 3.1416'
S := Format('Hex: %x', [N]); // 'Hex: 2a'
S := Format('String: %s', ['Hello']); // 'String: Hello'
S := Format('Padded: %10d', [N]); // ' 42'
S := Format('Left: %-10d|', [N]); // '42 |'
S := Format('Multiple: %s=%d, %.2f', ['x', N, F]);
// FloatToStrF (precise float formatting)
S := FloatToStrF(F, ffFixed, 8, 2); // '3.14'
S := FloatToStrF(F, ffCurrency, 8, 2); // '$3.14'
S := FloatToStrF(1234567, ffNumber, 10, 0); // '1,234,567'
// date/time formatting
S := FormatDateTime('yyyy-mm-dd', D); // '2024-06-18'
S := FormatDateTime('hh:nn:ss', D); // '14:30:00'
S := FormatDateTime('dddd, mmmm d, yyyy', D); // 'Tuesday, June 18, 2024'
// string to number (throws on invalid)
N := StrToInt('123');
F := StrToFloat('3.14');
D := StrToDateTime('2024-06-18');
// safe parsing (TryStrTo...)
if TryStrToInt('123', N) then
WriteLn('Parsed: ', N);
if TryStrToInt('abc', N) then
WriteLn('Valid')
else
WriteLn('Invalid number');
// IntToStr, FloatToStr
WriteLn(IntToStr(42));
WriteLn(FloatToStr(3.14));
end;StringBuilderとTStringList
StringBuilder(可変)は大きな文字列を構築するループに効率的 — Appendは新しい文字列を作らずインプレースで変更。TStringListはDelphiのスイスアーミーナイフ:ソート、検索、key=valueペアの保持(Values[])、ファイルの読み込み/保存(1行1アイテム)、区切りテキストの分割(CommaText、DelimitedText)ができる文字列リスト。TStringListは0インデックス(SL[0])で文字列(S[1])と異なる。常にtry..finallyでFree。Delphiでテキストファイルとシンプルな設定を処理する最も一般的な方法。
uses
System.SysUtils, System.Classes;
var
sb: StringBuilder;
SL: TStringList;
i: Integer;
begin
// StringBuilder: efficient concatenation (mutable)
sb := StringBuilder.Create;
try
for i := 1 to 1000 do
sb.Append('Line ').Append(i).AppendLine; // chainable
WriteLn(sb.ToString);
finally
sb.Free;
end;
// TStringList: versatile string collection
SL := TStringList.Create;
try
// add items
SL.Add('apple');
SL.Add('banana');
SL.Add('cherry');
WriteLn(SL.Count); // 3
WriteLn(SL[0]); // 'apple' (0-indexed!)
// sort and find
SL.Sort;
SL.Sorted := True; // auto-sort on Add
idx := SL.IndexOf('banana'); // find (returns -1 if not found)
// comma-separated text
SL.CommaText := 'red,green,blue'; // split into items
WriteLn(SL.CommaText); // 'blue,green,red'
// key=value pairs
SL.Clear;
SL.Values['name'] := 'Alice';
SL.Values['age'] := '30';
WriteLn(SL.Values['name']); // 'Alice'
// file I/O (one line per item)
SL.SaveToFile('items.txt');
SL.LoadFromFile('items.txt');
// delimited text
SL.Delimiter := ';';
SL.DelimitedText := 'a;b;c';
finally
SL.Free;
end;
end;Char操作とエンコーディング
Charは2バイトUnicode文字。Ord()はコードポイントを取得、Char()は逆変換。IsDigit/IsLetter/IsWhiteSpace/IsUpper/IsLowerが文字を分類。ToUpper/ToLowerがケースを変換。TEncoding.UTF8.GetBytesが文字列をバイト配列に変換(ファイルI/Oとネットワーキングに不可欠)— UTF-8は1文字あたり1-4バイト使用。TEncoding.UnicodeはUTF-16 LE(常に2バイト/文字)。Base64(TNetEncoding.Base64)はバイナリデータをテキストとして転送用にエンコード。StringとCharは内部的にUTF-16、ファイルストレージとネットワークプロトコルにはUTF-8に変換。
var
C: Char;
S: string;
Bytes: TBytes;
i: Integer;
begin
C := 'A';
WriteLn(Ord(C)); // 65 (ASCII/Unicode code point)
WriteLn(Char(66)); // 'B' (code point to char)
// char classification
WriteLn(IsDigit('5')); // TRUE
WriteLn(IsLetter('A')); // TRUE
WriteLn(IsWhiteSpace(' ')); // TRUE
WriteLn(IsUpper('A')); // TRUE
WriteLn(IsLower('a')); // TRUE
// case conversion
WriteLn(ToUpper('a')); // 'A'
WriteLn(ToLower('A')); // 'a'
// iterate characters
S := 'Hello';
for C in S do
Write(C, '(', Ord(C), ') ');
WriteLn; // H(72) e(101) l(108) l(108) o(111)
// string <-> bytes (encoding)
Bytes := TEncoding.UTF8.GetBytes('Hello');
WriteLn(Length(Bytes)); // 5 (ASCII chars are 1 byte in UTF-8)
Bytes := TEncoding.UTF8.GetBytes('héllo');
WriteLn(Length(Bytes)); // 6 (é is 2 bytes in UTF-8)
S := TEncoding.UTF8.GetString(Bytes); // back to string
// other encodings
Bytes := TEncoding.ASCII.GetBytes('Hello');
Bytes := TEncoding.Unicode.GetBytes('Hello'); // UTF-16 LE (2 bytes/char)
// Base64 encoding (for binary in text)
uses System.NetEncoding;
var B64: string := TNetEncoding.Base64.EncodeBytesToString(Bytes);
var Decoded: TBytes := TNetEncoding.Base64.DecodeStringToBytes(B64);
// char arrays
var Chars: array[0..4] of Char;
Chars[0] := 'H'; Chars[1] := 'e'; Chars[2] := 'l'; Chars[3] := 'l'; Chars[4] := 'o';
S := String(Chars); // convert char array to string
end;正規表現
System.RegularExpressionsがパターンマッチング用のTRegexを提供。IsMatchがテスト、Matchが最初を検索、Matchesがすべてを検索。グループは括弧で部分をキャプチャ — Groups[1]、Groups[2]でアクセス(1インデックス)。Replaceがマッチを置換($1、$2がグループを参照)。Splitがパターンで分割。一般的な正規表現:\d(数字)、\w(単語文字)、\s(空白)、+(1回以上)、*(0回以上)、{n}(ちょうどn回)、^/$(開始/終了)。roCompiledは繰り返し使用のためにコンパイルで高速化。ユーザー入力(メール、電話)は常に正規表現で検証。
uses
System.RegularExpressions;
var
Input, Pattern: string;
Match: TMatch;
Matches: TMatchCollection;
Result: string;
begin
Input := 'Phone: 123-456-7890, Zip: 10001';
// check if matches
if TRegEx.IsMatch(Input, 'd{3}-d{3}-d{4}') then
WriteLn('Found a phone number');
// find first match
Match := TRegEx.Match(Input, 'd{5}');
if Match.Success then
WriteLn('Zip: ', Match.Value); // '10001'
// find all matches
Matches := TRegEx.Matches(Input, 'd+');
for Match in Matches do
WriteLn(Match.Value); // 123, 456, 7890, 10001
// capture groups
Match := TRegEx.Match('2024-06-18', '(d{4})-(d{2})-(d{2})');
if Match.Success then
begin
WriteLn(Match.Groups[1].Value); // '2024' (year)
WriteLn(Match.Groups[2].Value); // '06' (month)
WriteLn(Match.Groups[3].Value); // '18' (day)
end;
// replace
Result := TRegEx.Replace(Input, 'd', 'X');
// 'Phone: XXX-XXX-XXXX, Zip: XXXXX'
// replace with match reference ($1, $2)
Result := TRegEx.Replace('John Doe', '(w+) (w+)', '$2, $1');
// 'Doe, John'
// split
var Parts: TArray<string>;
Parts := TRegEx.Split('a,b;;c', '[,;]+');
// common patterns
Pattern := '^[w.-]+@[w.-]+.w+$'; // email
Pattern := '^https?://[w./-]+$'; // URL
Pattern := '^d{3}-d{3}-d{4}$'; // US phone
// compiled regex (faster for repeated use)
var Regex := TRegEx.Create('d+', [roCompiled]);
try
Match := Regex.Match(Input);
finally
Regex.Free;
end;
end;配列、レコードとコレクション
静的配列と動的配列
静的配列はコンパイル時に固定サイズでカスタムインデックス範囲を持つ(array[0..4]またはarray[1..7])。動的配列(array of T)はSetLengthでサイズ変更可能 — 0インデックスで参照カウント付き。High()は最後のインデックスを返す、Length()はカウントを返す。既存の動的配列にSetLengthするとサイズ変更(拡大時に既存の値を保持)。nilで解放。動的配列リテラルは[1, 2, 3]を使用。多次元動的配列は'配列の配列'(ジャグ)— 各行が異なる長長さを持てる。
var
// static array (fixed size, compile-time)
Nums: array[0..4] of Integer; // 5 elements, indices 0..4
Matrix: array[0..2, 0..2] of Double; // 3x3 2D array
Days: array[1..7] of string; // 1-indexed (custom range)
// dynamic array (resizable at runtime)
Dyn: array of Integer;
Dyn2D: array of array of Integer; // jagged 2D
i, j: Integer;
begin
// static array
Nums[0] := 10;
Nums[1] := 20;
for i := 0 to High(Nums) do // High(Nums) = 4
WriteLn(Nums[i]);
WriteLn(Length(Nums)); // 5
// dynamic array
SetLength(Dyn, 5); // allocate 5 elements (0-indexed)
Dyn[0] := 1;
Dyn[1] := 2;
for i := 0 to High(Dyn) do
WriteLn(Dyn[i]);
SetLength(Dyn, 10); // resize (preserves existing values)
WriteLn(Length(Dyn)); // 10
Dyn := nil; // free memory
// dynamic array literal (modern Delphi)
Dyn := [1, 2, 3, 4, 5];
WriteLn(Length(Dyn)); // 5
// 2D dynamic array
SetLength(Dyn2D, 3); // 3 rows
for i := 0 to 2 do
begin
SetLength(Dyn2D[i], 3); // 3 cols per row
for j := 0 to 2 do
Dyn2D[i][j] := i * 3 + j;
end;
// array slice (Open Array)
WriteLn(Length(Dyn)); // 5
end;レコード(構造体)
レコードは値型(代入時にコピー、スタック割り当て)— Cのstructのようなもの。モダンDelphiのレコードはメソッド、プロパティ、可視性(private/public)を持てる。レコードは解放不要(ヒープ割り当てなし)。バリアントレコード(case...of)はフィールドがメモリを共有するユニオンを作成 — 型タグに便利。小さく軽量なデータ(ポイント、座標、設定)にはレコードを使用。継承やポリモーフィズムが必要な大きなオブジェクトにはクラスを使用。レコードは高速(ヒープ割り当てなし)だが継承不可。
type
// simple record (like a struct)
TPoint = record
X, Y: Integer;
end;
// record with methods (modern Delphi)
TPerson = record
Name: string;
Age: Integer;
// methods
function Greet: string;
procedure Birthday;
// properties
property IsAdult: Boolean read GetIsAdult;
private
function GetIsAdult: Boolean;
end;
// variant record (union — fields share memory)
TValue = record
case IsInt: Boolean of
True: (IntVal: Integer);
False: (FloatVal: Double);
end;
// implementing record methods
function TPerson.Greet: string;
begin
Result := 'Hi, I am ' + Name;
end;
procedure TPerson.Birthday;
begin
Inc(Age);
end;
function TPerson.GetIsAdult: Boolean;
begin
Result := Age >= 18;
end;
var
P: TPerson;
Pt: TPoint;
V: TValue;
begin
// record assignment copies all fields (value type)
P.Name := 'Alice';
P.Age := 30;
WriteLn(P.Greet); // Hi, I am Alice
P.Birthday;
WriteLn(P.Age); // 31
WriteLn(P.IsAdult); // TRUE
// record constructors (modern Delphi)
P := TPerson.Create; // zero-initializes
P.Name := 'Bob';
// variant record
V.IsInt := True;
V.IntVal := 42;
WriteLn(V.IntVal); // 42
V.IsInt := False;
V.FloatVal := 3.14;
WriteLn(V.FloatVal); // 3.14
end;セットと列挙型
セットはDelphiのユニークな機能 — 列挙型または部分範囲からの値のコレクション(最大256要素)。演算子:+(和集合)、-(差集合)、*(積集合)、=(等価)、<=(部分集合)、in(所属)。Include/Excludeは効率的な単一要素の追加/削除。セットはビットマップとして保存(非常に高速)。一般的な使用:TFontStyles(fsBold、fsItalic)、検証用のCharのセット(['0'..'9'])、曜日。列挙型は順序型 — Low()からHigh()で反復、GetEnumNameで文字列に変換。セットはフラグの組み合わせをエレガントで型安全にする。
type
// enumeration
TDay = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
TColor = (Red, Green, Blue);
// set type (collection of enum values)
TDays = set of TDay;
TColors = set of TColor;
TChars = set of Char; // set of characters
var
Weekdays: TDays;
MyColors: TColors;
D: TDay;
Digits: TChars;
C: Char;
begin
// set operations
Weekdays := [Mon, Tue, Wed, Thu, Fri];
MyColors := [Red, Blue];
// add and remove
Include(Weekdays, Sat); // Weekdays := Weekdays + [Sat]
Exclude(Weekdays, Sun); // Weekdays := Weekdays - [Sun]
// set operators
Weekdays := Weekdays + [Sat]; // union
Weekdays := Weekdays - [Sat]; // difference
Weekend := [Sat, Sun];
if Weekdays * Weekend = [] then // intersection is empty
WriteLn('No overlap');
// membership test
if Mon in Weekdays then
WriteLn('Monday is a weekday');
// iterate enum
for D := Low(TDay) to High(TDay) do
WriteLn(D); // 0 1 2 3 4 5 6 (ord values)
// convert enum to string
WriteLn(GetEnumName(TypeInfo(TDay), Ord(Mon))); // 'Mon'
// set of Char (common for validation)
Digits := ['0'..'9'];
C := '5';
if C in Digits then
WriteLn('Is a digit');
// set comparison
if MyColors = [Red, Blue] then
WriteLn('Equal sets');
if [Red] <= MyColors then // subset
WriteLn('Red is included');
end;TList、TDictionaryとジェネリクス
System.Generics.Collectionsが型安全なコレクションを提供:TList<T>(動的配列)、TDictionary<K,V>(ハッシュマップ)、TQueue<T>(FIFO)、TStack<T>(LIFO)、THashSet<T>(一意要素)。すべてジェネリック(コンパイル時型チェック、キャストなし)。TListはAdd/Remove/Delete/Sort/Contains/IndexOfを持つ。TDictionaryはAdd/Remove/TryGetValue/Keys/Valuesを持つ。TObjectList<T>はオブジェクトを所有(自動的に解放)— リストがオブジェクトのライフタイムを管理すべき場合に使用。常にtry..finallyでFree(これらはレコードではなくオブジェクト)。
uses
System.Generics.Collections;
var
Nums: TList<Integer>;
Ages: TDictionary<string, Integer>;
Unique: THashSet<string>;
Queue: TQueue<string>;
Stack: TStack<Integer>;
i: Integer;
K: string;
V: Integer;
begin
// TList<T>: dynamic array (generic)
Nums := TList<Integer>.Create;
try
Nums.Add(1);
Nums.Add(2);
Nums.AddRange([3, 4, 5]);
WriteLn(Nums.Count); // 5
WriteLn(Nums[0]); // 1 (0-indexed)
Nums[0] := 100;
Nums.Remove(2); // by value
Nums.Delete(0); // by index
Nums.Sort; // sort in place
Nums.Reverse;
if Nums.Contains(3) then
WriteLn('Found');
for i in Nums do
WriteLn(i);
finally
Nums.Free;
end;
// TDictionary<TKey, TValue>: hash map
Ages := TDictionary<string, Integer>.Create;
try
Ages.Add('Alice', 30);
Ages.Add('Bob', 25);
Ages['Eve'] := 28; // add or update
if Ages.TryGetValue('Alice', V) then
WriteLn('Alice is ', V); // 30
for K in Ages.Keys do
WriteLn(K);
for V in Ages.Values do
WriteLn(V);
Ages.Remove('Bob');
finally
Ages.Free;
end;
// TQueue<T> (FIFO) and TStack<T> (LIFO)
Queue := TQueue<string>.Create;
try
Queue.Enqueue('first');
Queue.Enqueue('second');
WriteLn(Queue.Dequeue); // 'first'
finally
Queue.Free;
end;
// TObjectList<T> (owns its objects — frees them on Clear/Free)
// uses System.Generics.Collections;
// var People: TObjectList<TPerson>;
// People := TObjectList<TPerson>.Create;
// People.Add(TPerson.Create); // freed when People is freed
end;配列アルゴリズムとソート
TArrayは配列操作のユーティリティクラス:Sort(オプションのカスタムIComparer付き)、BinarySearch(ソート済み配列の高速検索)、Reverse、Copy。TComparer<T>.Constructがインラインで比較関数を作成(匿名メソッド)。フィールドでソートするにはカスタム比較子が必要。BinarySearchはBooleanと見つかったインデックスを返す — 配列は事前にソート済みでなければならない。複雑な検索にはBreak付きの線形ループがシンプルで明確。TArray.Sortはクイックソート(平均O(n log n))。
uses
System.Generics.Collections, System.Generics.Defaults;
var
Nums: TArray<Integer>;
People: TArray<TPerson>;
i: Integer;
begin
// sort an array
Nums := TArray<Integer>.Create(5, 3, 1, 4, 2);
TArray.Sort<Integer>(Nums);
// Nums = [1, 2, 3, 4, 5]
// sort descending (custom comparer)
TArray.Sort<Integer>(Nums, TComparer<Integer>.Construct(
function(const L, R: Integer): Integer
begin
Result := R - L; // reverse comparison
end));
// binary search (array must be sorted)
TArray.Sort<Integer>(Nums);
var Found: Boolean := TArray.BinarySearch<Integer>(Nums, 3, i);
if Found then
WriteLn('Found at index ', i);
// sort array of records by a field
type TPerson = record Name: string; Age: Integer; end;
SetLength(People, 3);
People[0] := TPerson.Create('Alice', 30);
People[1] := TPerson.Create('Bob', 25);
People[2] := TPerson.Create('Carol', 28);
TArray.Sort<TPerson>(People, TComparer<TPerson>.Construct(
function(const L, R: TPerson): Integer
begin
Result := L.Age - R.Age; // sort by age
end));
for i := 0 to High(People) do
WriteLn(People[i].Name, ': ', People[i].Age);
// reverse an array
TArray.Reverse<Integer>(Nums);
// copy an array
var Copy: TArray<Integer>;
Copy := Copy(Nums, 0, Length(Nums));
// find with a predicate
var FoundIdx: Integer := -1;
for i := 0 to High(People) do
if People[i].Age > 28 then
begin
FoundIdx := i;
Break;
end;
end;プロシージャ、関数とパラメータ
プロシージャと関数
プロシージャ(戻り値なし)と関数(値を返す)はDelphiのサブルーチン。Result変数が戻り値 — それに代入(関数は終了時に返す)。Exit()は値付きで即座に返す(モダン構文)。前方宣言により本体が定義される前に呼び出し可能(相互再帰に便利)。関数はレコード、配列、オブジェクトを含む任意の型を返せる。値なしのExitはプロシージャを離脱するだけ。Result変数は暗黙的に宣言され、戻り値の型に一致。
// Procedure: performs an action (no return value)
procedure Greet(Name: string);
begin
WriteLn('Hello, ', Name, '!');
end;
// Function: returns a value
function Add(A, B: Integer): Integer;
begin
Result := A + B; // Result is the return variable
// Exit(42); // alternative: return immediately with 42
end;
// Function with multiple return paths
function Classify(Score: Integer): string;
begin
if Score >= 90 then
Exit('A'); // return immediately
if Score >= 80 then
Exit('B');
Result := 'F'; // default return
end;
// Function returning a record
function MakePoint(X, Y: Integer): TPoint;
begin
Result.X := X;
Result.Y := Y;
end;
// forward declaration (use before full definition)
function Calc(X: Integer): Integer; forward;
procedure Demo;
var
Sum: Integer;
P: TPoint;
begin
Greet('Alice'); // procedure call
Sum := Add(3, 4); // function call
WriteLn(Sum); // 7
WriteLn(Classify(85)); // B
P := MakePoint(3, 4);
WriteLn(Calc(10));
end;
function Calc(X: Integer): Integer;
begin
Result := X * 2;
end;パラメータ:Const、Var、Out、Default
const:読み取り専用パラメータ(文字列/配列のコピーも回避 — 効率的)。var:参照渡し(呼び出し元の変数を変更 — C#のrefのようなもの)。out:出力専用(呼び出し元は初期化しない、関数が設定)。デフォルトパラメータは最後でなければならない。オープン配列パラメータ(array of T)は任意の配列またはリテラル[1,2,3]を受け入れる — 効率のためconstを使用。文字列と配列にはconstが推奨(コピーなし)、呼び出し元の値を変更する必要がある場合のみvarを使用。オープン配列は元の配列の範囲に関わらず0インデックス。