無料の開発環境 Delphi Starter Edition で Object Pascal 言語を優しく学ぶ 第6回 「文字列 と オブジェクト」

#Delphi Starter Edition チュートリアルシリーズ シーズン2 第6回 「文字列 と オブジェクト」
![image](https://qiita-image-store.s3.amazonaws.com/0/145847/e835cc98-bf97-ca44-2de3-82d2796c82dc.png)

2017年1月23日より [「Delphi / C++Builder Starter チュートリアルシリーズ」 シーズン2、](http://forms.embarcadero.com/starter-tutorial-webinar)全9回、3月27日まで、毎週月曜日、Delphiパートが 17時00分~17時20分、 リアルタイム放送スペシャルコンテンツが5分～10分、C++Builderパートが 17時30分~17時50分の時間割でお送りしています。

無料でダウンロード & 利用できる開発環境の[Delphi / C++Builder Starter エディション](https://community.embarcadero.com/my-blog-posts?view=entry&id=8915)を使用して、プログラミング言語のDelphi (Object Pascal ), C++の基礎を学ぶオンラインセッションです。

##使用したスライドなどの情報を掲載します。
###Webセミナースライド
第6回 「文字列 と オブジェクト」のスライドは下記アドレスよりご参照いただけます。

* http://www.slideshare.net/ssuser194f49/delphi-cbuilder-starter-2-delphi-6

###アジェンダ
* 今日のねらい
 * 文字列を知る
 * 文字列の操作
 * クラスとオブジェクトの概略を知る
* 実施内容
 * 文字列の型
 * 文字列の代入とヘルパーについて
 * クラスとオブジェクトの意味を知る
 *クラスの定義とオブジェクトの宣言


###開発環境インストール
[Delphi / C++Builder Starter チュートリアルシリーズ](https://community.embarcadero.com/manage-blog-posts?view=entry&id=9038) シーズン1 第1回 ‟無料で始めよう アプリ作成„をご参考になり、開発環境をインストールしてください。

##**以下、Delphi Webセミナーの本筋**
###**文字と符号化**
* 符号化
  * コンピュータ上で文字を表すために、数値化する方式を定めたもの
<p></p><br>
* 文字コード
  * 符号化方式に沿って文字を数値化したもの
<p></p><br>
* 符号化方式：符号化方式は複数あり、Delphiで使用する代表的なもの紹介
  * Shift_JIS : 日本環境で使用する文字を日本の規格（JIS）にのっとり符号化したもの
  * UTF-8: Unicodeで定めている世界の文字群を、1バイト~4バイトの可変長で符号化
  * UTF-16 : Unicodeで定めている世界の文字群を2バイトまたは4バイトで符号化

|文字|Shift_JIS|UTF-8|UTF-16|
|:-:|:-:|:-:|:-:|
|あ|0x82A0|0xE38182|0x3042|
|A|0x41|0x41|0x0041|
|⌘|- (未対応)|0xE28C98|0x2318|

###**文字列(型)**
* 文字の集合を扱うためのデータ型 
* プログラム上で文字を表示したりデータベース上でデータとして格納してあったり…
<p></p><br>
* 代表的な文字列(文字）の型
  * String型 ( = UnicodeString型)
        * 最も一般的。 UTF-16 符号化形式のコードで文字列を格納する
<p></p><br>
  * UTF8String型
        * UTF-8符号化形式のコードで文字列を格納する
<p></p><br>
  * AnsiString型
        * 日本語環境下ではデフォルトとしてShift_JIS 符号化のコードで文字列を格納する
        * 各種指定の符号化（例：EUC-JP）などを設定することも可能 
        * UTF-8型の符号化を指定することも可能。これが実際には UTF-8String型 の正体 
<p></p><br>
  * Char や AnsiChar
        * これらは文字単体のデータ型：CharはUTF-16, AnsiChar日本語環境下のデフォルトでShift_JIS符号化コードを使用
<p></p><br>

###**文字列型の代入(暗黙の変換)**
* それぞれの文字列を相互に代入すると、可能な限り「文字」をキープする
  * String型 (UTF-16) <-> AnsiString型 (Shift_JIS) 
  *変換しても同じ文字をキープする（文字コード変換が行われる）
<p></p><br>
* Unicodeサポート文字で、Shift JISがサポートしていない文字の場合、Shift_JIS側では対象文字が失われる
  * String型 <-> UTF8String型 (UTF-8)
  * 変換しても同じ文字をキープする （文字コード変換が行われる）
  * 文字コードが違えどもUnicode文字はサポートされているので、文字が失われることはない
<p></p><br>
* UTF-8String型 <-> AnsiString型 (Shift_JIS) 
  * 変換しても同じ文字をキープする（文字コード変換が行われる）
  * Unicodeサポート文字で、Shift_JISがサポートしていない文字の場合、Shift_JIS側では対象文字が失われる
<p></p><br>
* 単に`' '`でくくっただけの文字 (例 str := ‘文字’;)
  * UTF-16 (UnicodeString)型の文字として扱われる(現行のDelphiでは文字はUTF16のUnicode文字として扱う)
  * 代入変換は String型と同じ

###**文字列型の代入 (コード例)**
* 文字列相互代入の例

```delphi
var
  sjis  : AnsiString;
  utf16 : string;
  utf8  : UTF8String;
begin
  sjis  := '⌘';     //Shift_JISにない文字なので文字化けする。 '??'に変換される
  utf16 := '⌘';     //Unicodeサポート文字につき問題なく‘⌘’が代入できる
  sjis  := utf16;    //utf16に入っている‘⌘’はShift_JISにない文字なので文字化けする。 '??'に変換される
  utf8  := utf16;    //utf16に入っている‘⌘’はUnicodeサポート文字につき問題なく代入できる
  sjis  := '日本語';  //SJISサポート範囲なので、問題なく‘日本語’が代入できる
  utf16 := sjis;     //Unicode文字はほぼSJISサポート文字を網羅しているので代入可能
  utf8  := utf16:    //Unicodeサポート文字につき問題なく‘日本語’が代入できる
end;
```

###**文字列から文字単体へのアクセス**
* 文字列の一つ一つにはインデックスでアクセス可能
* 先頭の文字のインデックスは`Low(string)`で取る

```delphi
//文字列の先頭インデックスと、インデックスを使って文字一つの要素にアクセス
procedure TForm1.Button1Click(Sender: TObject);
var
  str: String;
  I : Integer;
begin
  str := 'Hello Delphi world';
  I := Low(str); //Low(string)を使用すると先頭インデックスが返る
  ShowMessage(Str[I] + ' / Index:' + I.ToString ); //インデックスを使ってアクセス
end;
```
![image](https://qiita-image-store.s3.amazonaws.com/0/145847/b126a938-3b8b-9624-71a3-a10e3a1dd977.png)

###**文字列型の代入と連結**
文字列の代入には代入演算子  `:=` を使用可能
文字列の結合には `+`が使用可能

```delphi
//演算子を使って文字列の代入と結合が可能
procedure TForm1.Button1Click(Sender: TObject);
var
  str1, str2: String;
begin
  str1 := 'Hello';
  str2 := 'Delphi';
  str1 := str1 + str2;
  ShowMessage(Str1); // HelloDelphi と表示される
end;
```
![image](https://qiita-image-store.s3.amazonaws.com/0/145847/12fcf7aa-2394-d324-386b-e98dd07b96c3.png)

###**文字列のヘルパー**
* 文字列操作に絶大な効力を発揮
* 一例を紹介


|メソッド|説明|
|:---|:------|
[Copy](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.Copy) | 0 基準の指定された文字列を、コピーして返します。 |
[Equals](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.Equals)|指定された 2 つの 0 基準の文字列が同一かどうかを返します。 |
|[IsEmpty](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.IsEmpty) |0 基準の文字列が空（文字を含んでいない）かどうかを返します。 |
|[Replace](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.Replace)|それまでの文字または文字列を、新しく指定された文字または文字列で置換します。 |
|[Split](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.Split)| この 0 基準の文字列をサブ文字列に、指定された Separator を使用して分けます。 |
|[ToCharArray](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.ToCharArray)| この 0 基準の文字列を TArray<Char>（1 文字配列）に変換し、それを返します。 |
[ToUpper](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.ToUpper)| この 0 基準の文字列を、すべて大文字の文字列に変換して、それを返します。 |
|[Trim](http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper.Trim)| この 0 基準の文字列から、前後の空白を取り除き、文字群を制御します。 )

* コード使用例

```delphi
str := 'Happy Birthday Delphi!';
  ShowMessage(UpperCase(str)); //UpperCaseで大文字に変換
```
![image](https://qiita-image-store.s3.amazonaws.com/0/145847/6c1fd5ec-4777-c145-4985-d7618d2c0539.png)
参考docwiki: http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.TStringHelper_Methods

###**Format関数**
* 設定した書式に基づいて、一連の因数を文字列化する関数

```delphi
//Formatの構文
Format('文字列および書式', [文字列に組みこむデータたちをカンマで区切って連ねる]);
```

* 文字列に組み込む書式は`%`(パーセント文字）の後に設定

```delphi
//Formatはこんな感じで使えます
var
  str1, str2 : String;
  I : Integer;
begin
  str1 := '雨';
  I := 16;
  str2 := Format('明日の天気は%s、気温は%d度になるでしょう',[str1, I]);
  ShowMessage(str2);
end; 
```
![image](https://qiita-image-store.s3.amazonaws.com/0/145847/bc5e4f1e-9985-80ba-6dd8-b4c2d5f8cc32.png)
参考Docwiki: http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.Format

###**クラスとオブジェクト**
* クラス・オブジェクトとは
  * 任意のデータ型（フィールド）を保持できる
  * データにアクセス、処理するルーチン（メソッド）を持つ
  * 独自のフィールドとメソッドを保持するための、ひとかたまり（クラス）
<p></p><br>
* データの隠蔽、クラスの継承ができる（隠蔽・継承は翌週説明予定）
  * 他のユニットやクラスからフィールド・メソッドへのアクセス制限を行える
  * 既存のクラスのフィールド・メソッドを保持しつつ、新しいフィールド・メソッドを追加した新しいクラスを構築することができる
<p></p><br>
* クラスとオブジェクトの関係
  * クラスとしてユーザー定義されたデータ型が「クラス」
  * クラスの定義を使用するときの実体（インスタンス とも言います）が「オブジェクト」
  * 今まで使用してきた「データ型」と「変数」の関係とほぼ同じ。 データ型を→ クラス ・変数を→ オブジェクト

###**クラスの定義とオブジェクトの宣言方法**
* `type`ブロックでクラスを定義
* `var`ブロックでオブジェクトの識別子を宣言
    * オブジェクトは「参照型」なので、この宣言では参照を保持する変数を確保したのみ
    * 動的配列の`SetLength`同様に「実体」（インスタンス）を作る必要がある
<p></p><br>
* クラスは`Create`コンストラクタを使い、そのクラスの型のメモリを確保
* オブジェクト識別子に`Create`で確保した「実体」の参照（データの場所）を代入して使う
* 使い終わったオブジェクトは`Free` を使い、確保したメモリを解放してフリーにする

###**クラスの定義とオブジェクトの宣言の構文（基本）**
* クラス定義の構文(基本）
  * クラス定義の識別子は慣例的に接頭に Tを使う （`TMyClass` とか `TMyForm`) 

```delphi
type //typeブロックでクラス定義を行う
  クラス定義識別子 = class //’class’でクラスであることの定義を意味する
    フィールド識別子: フィールドデータ型; //クラスで保持するデータ（フィールド）の定義
    procedure メソッド識別子(パラメータ:パラメータデータ型); //クラスに紐づいたメソッド
    {クラス定義内ではメソッドも定義のみ。実装はimplementationブロックで行う}
    function メソッド識別子(パラメータ:パラメータデータ型): 戻りデータ型;
  end; //クラス定義もend;で締める
```
```delphi
var //varブロックでオブジェクトの識別子宣言を行う
  オブジェクト識別子 : クラス定義識別子;   {ここではオブジェクトの参照を保存するための識別子を宣言したのみ}
begin
  オブジェクト識別子 := クラス定義識別子.Create; {これでクラスの実データ領域（インスタンス）を確保して、その参照をオブジェクト識別子に代入した}
  オブジェクト識別子.Free; // これでオブジェクトのために確保したメモリを解放
end; 
```

###**クラス定義とオブジェクト宣言、使用と解放のコード例**
* コード例

```delphi
type //typeブロックでクラス定義を行う
  TDate = class //Tdateというクラス定義識別子を、「 = class 」としてクラス定義
    Year, Month, Day: Integer; //クラスで保持するデータ（フィールド）の定義
    procedure SetValue(Y, M, D: Integer); //クラスに紐づいたメソッド
    {クラス定義内ではメソッドも定義のみ。実装は implementation ブロックで行う}
    function UruuDoshi: Boolean;
  end; //クラス定義もend;で締める
```
```delphi
procedure TForm1.Button1Click(Sender: TObject);
var //varブロックでオブジェクトの識別子宣言を行う
  Birthday : TDate; {ここではオブジェクトの参照を保存するための識別子を宣言したのみ}
begin
  Birthday := TDate.Create; {これでオブジェクトの実データ（インスタンス）を確保して、その参照をオブジェクト識別子に代入した}
  Birthday.SetValue(1995, 2, 14);
  if Birthday.UruuDoshi then ShowMessage('うるうどしです')
  else ShowMessage('うるうどしではない');
  Birthday.Free; // これでオブジェクトのために確保したメモリを解放
end; 
```

###**クラスのメソッド実装例**
* 実装例

```delphi
implementation //implementation ブロック
{$R *.fmx}

procedure TDate.SetValue(Y, M, D: Integer); {クラス定義識別子.(ドット)メソッド定義識別子の形式で実装。TDateクラス定義のSetValueメソッド実装という意味}
begin
  Year := Y; //メソッド実装内ではクラスの定義識別子なしでフィールドを使用可能
  Month := M;
  Day := D;
end;

function TDate.Uruudoshi: Boolean; {クラス定義識別子.(ドット)メソッド定義識別子の形式で実装。TDateクラス定義のuruudoshiメソッド実装という意味.戻り値型は Boolean}
begin
  Result := IsLeapYear(Year); //System.SysUtilsに入っているうるう年チェック関数
end;
```
参考 SysUtilsについて：http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils

###**実は既にクラスは使用しています**
* 自動的に作成されたフォームもクラス
* 追加しているボタンなどのコンポーネントもクラス
* ボタンクリックなどのイベントハンドラもクラスに紐づいたメソッド
* イベントハンドラの実装（ボタンクリック時の動作などのプログラム）もメソッドの実装

```delphi
//マルチデバイスアプリケーションを作成すると自動的に作られているForm1も、TFormクラスを継承したTForm1クラス識別子の定義
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;
```

###**private, public , protected… 隠蔽と公開**
* `private`, `public` , `protected` キーワードとは何か？
  * 他ユニット上からのフィールドやメソッドのアクセスを制限、公開するためのキーワード
  * `private` → 他ユニットからは参照できず、アクセスもできない
  * `public` → 他ユニットから参照、アクセス可能
  * `protected` → 他ユニットからは使用できない、当クラスを継承するクラスで参照・アクセス可能
<p></p><br>
* アクセス制限を行うと…
  * 外部からフィールドをアクセスさせないことにより、直接参照されなくなる
  * 将来的なコードの改変時に直接アクセスされない内部フィールドなどは、コード改変の影響が少ない

##おわりに
第6回 2月27日分の Delphiパート「文字列 と オブジェクト」は以上です。
[＜＜シーズン2 第5回の記事はこちら](http://qiita.com/kazaiso/items/3a648e9302cf27688b08)

[シーズン2 第7回の記事（その1）はこちら＞＞](http://qiita.com/kazaiso/items/c76eac60bdd4dd075fa3)