Delphi XE8で正規表現を使って日本語(ひらがな・カタカナ・漢字)を抽出するには

正規表現に次の文字を使用できます。

ひらがな…\p{Hiragana}
カタカナ…\p{Katakana}
漢字…\p{Han}

これを使うとひらがな・カタカナ・漢字を抽出できます。

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, RegularExpressions;

const
  Target = '1あ2い3漢a字bカcナ';
  Pattern = '[\p{Hiragana}|\p{Katakana}|\p{Han}]';

var
  match: TMatch;
  matches: TMatchCollection;
begin
  matches := TRegEx.matches(Target, Pattern);
  for match in matches do
    WriteLn(Format('%s (%d, %d)', [match.Value, match.Index, match.Length]));
end.

実行結果

あ (2, 1)
い (4, 1)
漢 (6, 1)
字 (8, 1)
カ (10, 1)
ナ (12, 1)

Delphi XE8のFiremonkey AndriodアプリケーションでGmailに添付されたファイルを開くには

AndroidのGmailアプリで添付ファイルを開いたときに、Firemonkeyアプリケーションで内容を表示する方法です。
今回はCSVファイルを開くアプリケーションを作成します。

Android 4.4.2とAndroid 5.1.1で動作を確認しました。
Inboxアプリでも動作することを確認しました。

最初に、CSVファイルのIntentを受け取ることができるように、AndroidManifest.template.xmlを編集します。
AndroidManifest.template.xmlはプロジェクトをビルドすると生成されます。

AndroidManifest.template.xmlをエディタで開き、次の行を追加します。
CSVファイルを対象としているため、mimeTypeは”text/csv”にしています。

        <intent-filter>  
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/csv" />
        </intent-filter> 

アプリケーションがアクティブになったときのイベントを取得できるようにします。

type
  TForm2 = class(TForm)
    procedure FormCreate(Sender: TObject);
    …
    function HandleAppEvent(AAppEvent: TApplicationEvent;
      AContext: TObject): Boolean;
  end;

procedure TForm2.FormCreate(Sender: TObject);
var
  AService: IFMXApplicationEventService;
begin
  if TPlatformServices.Current.SupportsPlatformService
    (IFMXApplicationEventService, IInterface(AService)) then
    AService.SetApplicationEventHandler(HandleAppEvent)
end;

function TForm2.HandleAppEvent(AAppEvent: TApplicationEvent;
  AContext: TObject): Boolean;
begin
  if AAppEvent = TApplicationEvent.BecameActive then
  begin
    //アプリケーションがアクティブになったときの処理
  end;
end;

Intentを受信する処理を記述します。

function TForm2.HandleAppEvent(AAppEvent: TApplicationEvent;
  AContext: TObject): Boolean;
var
  Intent: JIntent;
  AttachmentFileName: string;
  CSV: string;
begin
  if AAppEvent = TApplicationEvent.BecameActive then
  begin
    Intent := SharedActivity.getIntent;
    if Intent <> nil then
    begin
      if TJIntent.JavaClass.ACTION_VIEW.equals(Intent.getAction) then
      begin
        // 添付ファイルのファイル名
        AttachmentFileName := GetDisplayName(Intent.getData);
        // 添付ファイルのファイル名をMemo1に出力
        Memo1.Lines.Add('ファイル名=' + AttachmentFileName);

        // 添付ファイルの内容
        if StringToJString('content').equals(Intent.getScheme) then
        begin
          // 添付のCSVファイルのデータ
          CSV := GetContent(Intent);
          // 添付ファイルの内容をMemo1に出力
          Memo1.Lines.Add('添付のCSVファイルのデータ');
          Memo1.Lines.Add(CSV);
        end;

      end;
    end;
  end;
  Result := True;
end;

添付ファイルのファイル名を取得する関数です。

/// <summary>
/// 添付ファイルのファイル名を取得する
/// </summary>
function GetDisplayName(Uri: Jnet_Uri): string;
var
  Cursor: JCursor;
  ColumnIndex: Integer;
begin
  if Uri = nil then
    Exit;

  Cursor := SharedActivity.getContentResolver.query(Uri, nil, nil, nil, nil);
  Cursor.moveToFirst;
  ColumnIndex := Cursor.getColumnIndex
    (TJMediaStore_MediaColumns.JavaClass.DISPLAY_NAME);
  if ColumnIndex >= 0 then
  begin
    // 添付ファイルのファイル名
    Result := JStringToString(Cursor.GetString(ColumnIndex));
  end;
  Cursor.close;
end;

添付のCSVファイルのデータを取得する関数です。

/// <summary>
/// 添付のCSVファイルのデータを取得する
/// </summary>
function GetContent(Intent: JIntent): string;
var
  InputStream: JInputStream;
  Buffer: TArray<System.Byte>;
begin
  InputStream := SharedActivity.getContentResolver.openInputStream
    (Intent.getData);
  Buffer := JInputStreamToByteArray(InputStream);
  // 文字コードはUTF-8決め打ち
  Result := TEncoding.UTF8.GetString(Buffer);
end;

InputStreamのデータを取得してバイト配列を返す関数です。

/// <summary>
/// InputStreamのデータを取得してバイト配列を返す
/// </summary>
function JInputStreamToByteArray(InputStream: JInputStream)
  : TArray<System.Byte>;
var
  List: TList<System.Byte>;
  I: Integer;
begin
  List := TList<System.Byte>.Create;
  try
    while True do
    begin
      I := InputStream.read;
      if I < 0 then
        Exit(List.ToArray);
      List.Add(System.Byte(I));
    end;
  finally
    List.Free;
  end;
end;

以上で完成です。

Gmailアプリで、CSVファイルを開きます。

intent-1

Firemonkeyアプリケーションが起動し、添付ファイルのファイル名と内容が表示されました。

intent-2

Delphi XE8のFiremoneky AndroidアプリケーションでIntentを受信するには

Delphi XE8のFiremoneky AndroidアプリケーションでIntentを受信する方法です。

Intentを送信するアプリケーション

最初に文字列をIntentで送信するサンプルプログラムを作成します。
このサンプルプログラムで送信した文字列を受信するアプリケーションを作成します。

フォームにTButtonコンポーネントを一つ配置します。

uses
  Androidapi.JNI.GraphicsContentViewText, // JIntent
  Androidapi.Helpers; // StringToJString

procedure TForm1.Button1Click(Sender: TObject);
var
  sendIntent: JIntent;
begin
  sendIntent := TJIntent.Create;
  sendIntent.setAction(TJIntent.JavaClass.ACTION_SEND);
  sendIntent.putExtra(TJIntent.JavaClass.EXTRA_TEXT, StringToJString('テスト'));
  sendIntent.setType(StringToJString('text/plain'));
  SharedActivity.startActivity(sendIntent);
end;

Intentを受信するアプリケーション

次にIntentを受信するアプリケーションを作成します。

新規にアプリケーションを作成し、TMemoコンポーネントを配置します。

Intentを受信するアプリケーションのAndroidManifest.template.xmlを編集します。
AndroidManifest.template.xmlはプロジェクトをビルドすると生成されます。

AndroidManifest.template.xmlをエディタで開き、次の行を追加します。

        <intent-filter>  
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
            <action android:name="android.intent.action.SEND" /> <=追加
            <category android:name="android.intent.category.DEFAULT" /> <=追加
            <data android:mimeType="text/*" /> <=追加
        </intent-filter> 

アプリケーションがアクティブになったときのイベントを取得できるようにします。

type
  TForm2 = class(TForm)
    procedure FormCreate(Sender: TObject);
    …
    function HandleAppEvent(AAppEvent: TApplicationEvent;
      AContext: TObject): Boolean;
  end;

procedure TForm2.FormCreate(Sender: TObject);
var
  AService: IFMXApplicationEventService;
begin
  if TPlatformServices.Current.SupportsPlatformService
    (IFMXApplicationEventService, IInterface(AService)) then
    AService.SetApplicationEventHandler(HandleAppEvent);
end;

function TForm2.HandleAppEvent(AAppEvent: TApplicationEvent;
  AContext: TObject): Boolean;
begin
  if AAppEvent = TApplicationEvent.BecameActive then
  begin
    //アプリケーションがアクティブになったときの処理
  end;
end;

Intentを受信する処理を記述します。

uses
  Androidapi.JNI.GraphicsContentViewText, // JIntent
  Androidapi.JNI.Os, // JBundle
  Androidapi.JNI.JavaTypes, // JString
  Androidapi.Helpers; // SharedActivity JStringToString

function TForm2.HandleAppEvent(AAppEvent: TApplicationEvent;
  AContext: TObject): Boolean;
var
  Intent: JIntent;
  Extras: JBundle;
  S: JString;
begin
  Result := False;

  if AAppEvent = TApplicationEvent.BecameActive then
  begin
    Intent := SharedActivity.getIntent;
    if Intent <> nil then
    begin
      if TJIntent.JavaClass.ACTION_SEND.equals(Intent.getAction) then
      begin
        Extras := Intent.getExtras;
        if Extras <> nil then
        begin
          S := Extras.getString(TJIntent.JavaClass.EXTRA_TEXT);
          if S <> nil then
          begin
            // 受信した文字列をMemo1に表示
            Memo1.Text := JStringToString(S);
          end;
        end;
      end;
    end;
  end;
end;

Intent送信側アプリケーションから送信すると、

intent-1

受信側アプリケーションで受信できました。

intent-2

2015年10月19日 追記:
アプリケーションが待機中の時にインテントを受信できていませんでした。
正しい方法は「Delphi 10 SeattleのAndroidアプリケーションでIntentの送受信をするには」をご覧ください。

Delphi XE8 FireMonkey – TStringGridのセル(Cell)の描画をカスタマイズする

Team Japan » FireMonkey – TStringGridのセル(Cell)の描画をカスタマイズする」をDelphi XE8で書き直してみました。

セルの描画をカスタマイズするには、グリッドのOnDrawColumnCellイベントにセルを描画する処理を記述します。

procedure TForm1.Grid1DrawColumnCell(Sender: TObject; const Canvas: TCanvas;
  const Column: TColumn; const Bounds: TRectF; const Row: Integer;
  const Value: TValue; const State: TGridDrawStates);
begin
  Canvas.Stroke.Kind := FMX.Graphics.TBrushKind.bkSolid; // 単色
  Canvas.Stroke.Color := TAlphaColorRec.Lime; // ライム色
  Canvas.StrokeThickness := 3; // ストロークアウトラインの幅
  Canvas.DrawRect(Bounds, 20, 20, AllCorners, 1.0, TCornerType.Round); // 楕円を描く
end;

grid-1

他の方法として、セルの描画をカスタマイズしたセルのクラスを作成します。

type
  /// <summary>
  /// 楕円を表示するセル
  /// </summary>
  TRoundCell = class(TTextCell, IDrawableCell)
  private
    procedure BeforeDrawing(const Canvas: TCanvas);
    procedure AfterDrawing(const Canvas: TCanvas);
    procedure DrawCell(const Canvas: TCanvas; const Bounds: TRectF;
      const Row: Integer; const Value: TValue; const State: TGridDrawStates);
  end;

procedure TRoundCell.AfterDrawing(const Canvas: TCanvas);
begin
end;

procedure TRoundCell.BeforeDrawing(const Canvas: TCanvas);
begin
end;

procedure TRoundCell.DrawCell(const Canvas: TCanvas; const Bounds: TRectF;
  const Row: Integer; const Value: TValue; const State: TGridDrawStates);
begin
  Canvas.Stroke.Kind := FMX.Graphics.TBrushKind.Solid; // 単色
  Canvas.Stroke.Color := TAlphaColorRec.Lime; // ライム色
  Canvas.StrokeThickness := 3; // ストロークアウトラインの幅
  Canvas.DrawRect(Bounds, 20, 20, AllCorners, 1.0, TCornerType.Round); // 楕円を描く

  Canvas.Fill.Color := TAlphaColorRec.Black;
  Canvas.FillText(Bounds, 'セルの値', False, AbsoluteOpacity, [], TTextAlign.Center);
end;

FMX.Grid.TStringColumnクラスを継承し、セルにTRoundCellクラスを使用する列。

type
  /// <summary>
  /// TRoundCellを使用する列
  /// </summary>
  TStringColumn = class(FMX.Grid.TStringColumn)
  protected
    function CreateCellControl: TStyledControl; override;
  end;

function TStringColumn.CreateCellControl: TStyledControl;
begin
  Result := TRoundCell.Create(Self);
end;

フォームにグリッドを配置し、グリッドにTStringColumnを追加します。

grid-3

grid-2