人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Delphiの質問です。

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


●質問者: SuzukiU
●カテゴリ:コンピュータ
✍キーワード:cool Delphi String あいうえお 文字列
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● matsu-boolean
●60ポイント ベストアンサー

一応 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で計算しているのでマイナスの値を返すことがあります。

◎質問者からの返答

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


2 ● quintia
●15ポイント

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が返ってきます。

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


3 ● quintia
●15ポイント

すみませんっ! 全然質問の意味を取り違えていました。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 で数字を取得できます。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ