Delphiの質問です。


数値ではない文字列(String)から、数値(Integer)を得るcoolな方法が知りたいです。文字列が「あいうえお」ならばx、文字列が「abcde」ならy、文字列が「12345」ならz、といったように、文字列が同じならば同じ数値を作り出したいです。現在はSoundExInt関数とLength関数を用いており、間に合ってはいるのですが、coolではないと感じており、もっとcoolな方法を知りたいです。

回答の条件
  • 1人2回まで
  • 登録:2007/10/30 08:20:00
  • 終了:2007/11/04 12:41:11

ベストアンサー

id:matsu-boolean No.1

matsu-boolean回答回数43ベストアンサー獲得回数72007/10/30 09:05:47

ポイント60pt

一応 Delphi 使いです。

wikipediaに載ってたハッシュ関数をDelphiで書き直してみました。

function hash(str: String): Integer;
var
  hash: Integer;
  idx: Integer;
begin
  hash := 0;
  for idx := 1 to Length(str) do
  begin
    hash := hash * 137 + ord(str[idx]);
  end;
  Result := hash mod 1987;
end;

http://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A...

最後の1987をもうちょっと大きな素数に変えればbit幅増やせるかな?と思います。というか、余りにする必要も無いかも?。

ちなみに Wikipedia版はunsignedですが、このDelphi版はIntegerで計算しているのでマイナスの値を返すことがあります。

id:SuzukiU

ありがとうございます。スタイリッシュで勉強になります。

2007/10/30 09:48:56

その他の回答(2件)

id:matsu-boolean No.1

matsu-boolean回答回数43ベストアンサー獲得回数72007/10/30 09:05:47ここでベストアンサー

ポイント60pt

一応 Delphi 使いです。

wikipediaに載ってたハッシュ関数をDelphiで書き直してみました。

function hash(str: String): Integer;
var
  hash: Integer;
  idx: Integer;
begin
  hash := 0;
  for idx := 1 to Length(str) do
  begin
    hash := hash * 137 + ord(str[idx]);
  end;
  Result := hash mod 1987;
end;

http://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A...

最後の1987をもうちょっと大きな素数に変えればbit幅増やせるかな?と思います。というか、余りにする必要も無いかも?。

ちなみに Wikipedia版はunsignedですが、このDelphi版はIntegerで計算しているのでマイナスの値を返すことがあります。

id:SuzukiU

ありがとうございます。スタイリッシュで勉強になります。

2007/10/30 09:48:56
id:quintia No.2

quintia回答回数560ベストアンサー獲得回数692007/10/30 15:11:25

ポイント15pt

TStringListクラスのObjectsプロパティを使う手があります。

文字列とひもづけて任意のオブジェクトを格納しておけるんです。

1つの数字を格納しておくオブジェクトを用意します(そんなオブジェクトがシステムにあったかどうか忘却の彼方ですので……)。

  TNumber = class
  public
    number: Integer;
    constructor Create(n: Integer);
  end;
:
:
constructor TNumber.Create(n: Integer);
begin
  number:=n;
end;

格納する手続きは、

addメソッドの返り値を取っておいて、Objectsプロパティのインデクスにして、TNumberのインスタンスを格納する。

取得する手続きは、

indexOfで項目位置を取得して、負数でなければObjectプロパティを読み取り、TNumberにキャストする。

です。


ソースはこんな感じ。

procedure TForm1.Button1Click(Sender: TObject);
var
  list: TStringList;
  idx: Integer;
  wk: TNumber;
begin
  list:=TStringList.Create;
  try
    //文字列と数字を関連づけていく
    idx:=list.Add('Foo');
    list.Objects[idx]:=TNumber.Create(10);

    idx:=list.Add('Bar');
    list.Objects[idx]:=TNumber.Create(20);

    idx:=list.Add('Baz');
    list.Objects[idx]:=TNumber.Create(30);

    //冗長に書いているけど、
    list.Objects[list.add('Fuga')]:=TNumber.Create(50);
    //でもいい


    //ソートしておくとindexOfが高速動作する(様な記憶がある)
    list.Sort;
    list.Sorted:=True;


    idx:=list.IndexOf('Baz');
    if idx >= 0 then
    begin
      wk:=TNumber(list.Objects[idx]);
      ShowMessage('みつかったのは'+IntToStr(wk.number));
    end
    else begin
      ShowMessage('not found');
    end;


  finally
    list.Free;
  end;
end;

ちゃんとBazから30を取得できます。



あと、ここからは全くお奨めしませんが、Objectsプロパティに整数値をキャストして強引に入れてしまうというのもあります。

procedure TForm1.Button2Click(Sender: TObject);
var
  list: TStringList;
  idx, wk: Integer;
begin
  list:=TStringList.Create;
  try
    //文字列と数字を関連づけていく
    //ここの TObject( ) は型キャスト! です
    idx:=list.Add('Foo');
    list.Objects[idx]:=TObject(10);

    idx:=list.Add('Bar');
    list.Objects[idx]:=TObject(20);

    idx:=list.Add('Baz');
    list.Objects[idx]:=TObject(30);

    //ソートしておくとindexOfが高速動作する
    list.Sort;
    list.Sorted:=True;

    idx:=list.IndexOf('Bar');
    if idx >= 0 then
    begin
      //このInteger( ) は型キャスト! です
      wk:=Integer(list.Objects[idx]);
      ShowMessage('みつかったのは'+IntToStr(wk));
    end
    else begin
      ShowMessage('not found');
    end;


  finally
    list.Free;
  end;
end;

ちゃんと20が返ってきます。

これは恐ろしく判りづらいので、長期的にあるいは他人が保守する必要がある場合はお奨めできませんが、メモリ効率はいいです。

id:quintia No.3

quintia回答回数560ベストアンサー獲得回数692007/10/30 16:34:16

ポイント15pt

すみませんっ! 全然質問の意味を取り違えていました。m(_ _)m


http://www.cityinthesky.co.uk/cryptography.html

でダウンロードできる、DCPcrypt v2 Beta 3 がハッシュを扱うためのコンポーネントになっています。

MIT license のオープンソースだそうです。

例えば TDCP_sha1 のコンポーネントと TEdit を1つずつ,フォームに貼り付けて、

procedure TForm1.Button1Click(Sender: TObject);
var
  digest: array[0..19] of Byte; //HashSizeが160(bit)なので20バイト分
  num: DWORD;
begin
  DCP_sha11.Init;

  DCP_sha11.UpdateStr(Edit1.Text);

  DCP_sha11.Final(digest);

  Move(digest, num, SizeOf(num));

  ShowMessage(IntToStr(num));
end;

という感じで試してみると、ハッシュの先頭から DWORD で数字を取得できます。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません