カテゴリー別アーカイブ: 未分類

Delphi2007の謎

SkRegExp を Delphi2007 でデバッグしているときにはまった。


var
  S: WideString;
begin
  S := #$0085;
  if S = #$0085 then
    ShowMessage('Match');
end;

これが Match を返すのは当然。

が、しかし。

デバッガで S の中をのぞくと $FB30 となっている。

もちろん、Delphi XE では $0085 。

この場合はマッチするからいい。

でも、SkRegExp では文字を UCS4Char に変換して比較する部分がある。

そこではマッチしない。

どうしたものか。

SkRegExp version 2.3.0 公開

SkRegExp version 2.3.0 を公開しました。

TSkRegExp クラスに EscapeRegExChars クラス関数を追加しました。

EscapeRegExpCharsは、メタ文字を通常の文字として変換するクラス関数です。

メタ文字を通常の文字として検索したい場合はこのクラス関数で変換すると手間が掛かりません。

たとえば、”(test)”を検索するとき。

“(“と”)”はメタ文字のため、”(test)”とエスケープする必要があります。

EscapeRegExpChars クラス関数はすべてのメタ文字をエスケープできます。

また、このバージョンからはヘルプファイルの添付を中止しました。

取扱説明書はこのサイトのドキュメントを参照して下さい。

SkRegExp version 2.3.0 はこちらからダウンロードできます。

DelphiXEどうしよう・・・

DelphiXEが発売された。

私が今使っているのはDelpi2009。Delphi2010へはバージョンアップしなかった。

XE は MacOS-X サポートがアナウンスされていた。Apple 信者としてはバージョンアップする気満々だった。

私が Mac を辞めたのは Delphi が使えなかったから。でも、Delphi が対応すれば話は別だ。

ところが、楽しみだった MacOS-X サポートは見送り。一気に購買意欲が萎えた。

がしかし。

いざ、発売されてみると、面白そうな昨日が満載でちょっと良さそうに見える。

それでも、MacOS-X サポート先送りは萎えた購買意欲はよみがえっていない。

さて、どうしたものか。

メールライブラリ

私は返信屋2007と言うソフトを売っています。このソフトは自前でSMTP、POP3、MIME解析を実装しています。

Delphiコミュニティーで、Indyを使って苦労してるのを見ると、私のライブラリにニーズがあるかな?と思うんですがどうですかね。

実は返信屋の次期バージョン用に、Unicode対応したライブラリを作成中なんですが、切羽詰ったことがないんで仕事が進まないんです。

今までソケットライブラリはSYNAPSEを使っていましたが、知的好奇心から自前で実装しました。SYNAPSEをハックして、OpenSSLにも対応しました。残念ながら日の目を見るにいたっていません。

ただし、これらのライブラリは巨大な上、不正なフォーマットのメールに「現実的な対応」を行ったため、非常に見通しの悪いライブラリになっています。

オープンソース化しても第三者が手を加えられなければあまり意味がないとも思うし。

それに作者自身の情熱の問題もあります。SkRegExpほどには思い入れがないという・・・。

Quick Search algorithm for Delphi

SkRegExp ばかり触っていると飽きてくるので、他の事をやってみる。

とは言っても SkRegExp がらみだが。

SkRegExp の最適化で、高速な文字列検索を実装したいと考えている。

Boyer-Moore より速いアルゴリズムがあると聞いたので、ネットで探してみた。

Quick Search と言うのが見つかった。

早速、Delphi に移植してみた。

最初、Unicode を使うには文字数分のテーブルが必要なのか?と思った。

もちろん、そんなもん非現実的だ。

そこで、効率は悪くなるが、下位バイトだけ使うことにして作ってみたのが以下のソース。

試してみたがやっぱり速い。

アルゴリズムそのままなので著作権は主張しない。自由に使ってください。

function QuickSearch(const AText, APattern: string): Integer;
var
  TextP, PatternP: PChar;
  SkipTable: array[0..256] of Integer;
  I, PatternLen, TextLen, Low: Integer;
begin
  Result := 0;
  PatternLen := Length(APattern);
  TextLen := Length(AText);
  if TextLen < PatternLen then
    Exit;
  {パターンが1文字ならQuick Seachの意味がない}
  if PatternLen = 1 then
  begin
    Result := Pos(APattern, AText);
    Exit;
  end;
  TextP := PChar(AText);
  PatternP := PChar(APattern);
  for I := 0 to 256 do
  SkipTable[I] := PatternLen + 1;
  for I := 0 to PatternLen - 1 do
  begin
    Low := Integer(PatternP[I]) and $FF;
    SkipTable[Low] := PatternLen - I;
  end;
  Result := 0;
  while Result < TextLen - PatternLen do
  begin
    if StrLComp(TextP + Result, PatternP, PatternLen) = 0 then
    begin
      Inc(Result);
      Exit;
    end;
    Low := Integer(TextP[Result + PatternLen]) and $FF;
    Inc(Result, SkipTable[Low]);
  end;
end;