[PHP] 文字列をもとに、一意となる短いキーを作りたいです。目的は、その文字列のファイル名のファイルを作りたいからです。


1) 2バイト文字を含む長い文字列がキーとなるデータがある
2) 1データ毎にファイルを作りたい
3) ファイル名長に制限があるのでキーとなる文字列を短くしたい

例)
キー「りんごのデータ」
キー「みかんのデータ」

キーを元に短い文字列を作成

キー「りんごのデータ」→ 短いキー「apple」
キー「みかんのデータ」→ 短いキー「orange」

ファイルを作成

apple.txt
orange.txt


データ取得時にはキーを使用

キー「りんごのデータ」から apple.txt を抽出


※このとき、キー←→短いキー(ファイル名)は可逆でどの方向にも
一意になるものとします。※


この、キーを生成するプログラムが知りたいです。


よろしくお願いいたします。

回答の条件
  • 1人2回まで
  • 登録:2006/06/02 01:04:54
  • 終了:2006/06/06 09:37:15

ベストアンサー

id:Chiether No.1

Chiether回答回数40ベストアンサー獲得回数12006/06/02 01:32:29

ポイント80pt

文字列長が不明なので厳密に一意というのは無理かと思います。

特に「長いキー」から「短いキー」にするという事は、その時点で可逆圧縮するので「結果、短くならない可能性」もあります。

なので私は代替しか提案できませんが、「変換履歴ファイル」を別に保存しておくのが一番だと思います。

 

[trans.dat]

0001,200606020116,りんごのデータ

0002,200606020132,みかんのデータ

これで 0001.txt, 0002.txt ... と生成していきます。

新しくキーが登録された場合は「行数」から連番を生成等でもかまいません。

 

あるいは、いっその事……このキー関連付けを連想配列にして動的に生成されるファイルをincludeするという荒業もあります。

※ 以下コード、面倒なので文字エスケープとか例外とか省略

[main.php]

include "trans.php";

echo $transdata[りんごのデータ];

 

[trans.php] (このファイルを動的に生成する)

$transdata["りんごのデータ"] = "apple";

$transdata["みかんのデータ"] = "orange";

// もしくは array関数で一度に登録

 

[addkey.php]

$key = "ぶどうのデータ";

$data = "grape";

$fp = fopen("trans.php","a");

fputs($fp,"transdata[\"$key\"] = \"$data\";\n");

// array関数で登録している場合はもうちょい複雑。

 

この荒業の欠点は、キーができればできるほどメモリ消費するという事です。

id:k2017

定義ファイルの作成は私も最初に考えました。ただ、書き忘れましたがキーは数十万件になり、少なくはないです。連想配列は思いつきませんでした。

大変参考になりました。ありがとうございます。実現方法のひとつとして考えたいと思います。

2006/06/02 02:14:43

その他の回答(2件)

id:Chiether No.1

Chiether回答回数40ベストアンサー獲得回数12006/06/02 01:32:29ここでベストアンサー

ポイント80pt

文字列長が不明なので厳密に一意というのは無理かと思います。

特に「長いキー」から「短いキー」にするという事は、その時点で可逆圧縮するので「結果、短くならない可能性」もあります。

なので私は代替しか提案できませんが、「変換履歴ファイル」を別に保存しておくのが一番だと思います。

 

[trans.dat]

0001,200606020116,りんごのデータ

0002,200606020132,みかんのデータ

これで 0001.txt, 0002.txt ... と生成していきます。

新しくキーが登録された場合は「行数」から連番を生成等でもかまいません。

 

あるいは、いっその事……このキー関連付けを連想配列にして動的に生成されるファイルをincludeするという荒業もあります。

※ 以下コード、面倒なので文字エスケープとか例外とか省略

[main.php]

include "trans.php";

echo $transdata[りんごのデータ];

 

[trans.php] (このファイルを動的に生成する)

$transdata["りんごのデータ"] = "apple";

$transdata["みかんのデータ"] = "orange";

// もしくは array関数で一度に登録

 

[addkey.php]

$key = "ぶどうのデータ";

$data = "grape";

$fp = fopen("trans.php","a");

fputs($fp,"transdata[\"$key\"] = \"$data\";\n");

// array関数で登録している場合はもうちょい複雑。

 

この荒業の欠点は、キーができればできるほどメモリ消費するという事です。

id:k2017

定義ファイルの作成は私も最初に考えました。ただ、書き忘れましたがキーは数十万件になり、少なくはないです。連想配列は思いつきませんでした。

大変参考になりました。ありがとうございます。実現方法のひとつとして考えたいと思います。

2006/06/02 02:14:43
id:i_kumagoro No.2

i_kumagoro回答回数170ベストアンサー獲得回数582006/06/05 14:00:10

ポイント5pt

ファイル名のバイト列を可逆圧縮してbase64みたいな方法で文字列化すれば一応目的の様な事はできるとは思います。しかし、Chietherさんが書かれた通りで、ファイル名がある一定の長さを越えない保証はありません。

やはり代替案になりますが、キーと短いキーとの対応表をデータベースに保存してはいかがでしょうか。大規模であればそっちの方がパフォーマンスがよくなります。

また、2.の要望には反しますが、いっその事データベースにファイルの内容も入れてしまえば、そもそも短いキーも作る必要がなくなります。

id:k2017

データベースと仰っているのは上で出ている定義ファイルと同じだと思います。レコード数が多い分パフォーマンスも低いです。同じことを書かないでください。

2006/06/06 09:35:01
id:zebevogue No.3

zebevogue回答回数65ベストアンサー獲得回数72006/06/06 02:11:51

ポイント1pt

完全に要望に一致するかわかりませんが、

md5を使えば一意で32文字固定になります。

但し、ハッシュなのでファイル名から元の文字への復元はできません。長い名前からハッシュは得られますから特定のファイルへのアクセスは問題ありません。

対策としてはファイルの中の1行目に長い名前自体を入れるとか、別ファイルやDBに対応表を格納していけばいいと思います(格納されていない組み合わせの場合は追加とか)。

id:k2017

復元できないのでは話しになりません。別ファイルの案は上で出ています。同じことを書かないでください。

2006/06/06 09:36:05
  • id:i_kumagoro
    回答の主旨が伝わっているのか不安ですので補足します。発想の根本的な部分はChietherさんの回答と同じですが、連想配列を使用した場合のメモリ消費の増大や、定義ファイルを使用したパフォーマンスの悪化に対する改善策としてデータベースの使用を提案しました。k2017さんのおっしゃる「レコード数が多い分パフォーマンスも低いです」はおそらく定義ファイルを使用した場合の事を指していると思いますが、レコード数が多くなれば、余程最適化したアルゴリズムを組むのでもなければデータベースを使用した方がパフォーマンスはよくなります。
    繰り返しになりますが、「データベースと仰っているのは上で出ている定義ファイルと同じ」という発言が根本的な発想が同じという意味であれば同意しますが、パフォーマンスも同じという主旨であればそうではない場合の方がはるかに多いです。
  • id:k2017
    ありがとうございます! ただ、データベース(定義ファイル)に入れるのであれば、IDを振ればいいのでわざわざ圧縮する必要がないですね。パフォーマンスは 圧縮>データベース>定義ファイルで同意です。
  • id:i_kumagoro
    データベースや定義ファイルを使用する場合は、もちろんファイル名の圧縮は必要ありません。データベースの利用については、そもそもファイル名の圧縮が最長字数の保証ができないので使えないという前提での話だと認識していたので、そのあたりは特に記述していないつもりでした。
    しかし、確かに私の回答を見ると「短いキー」はファイル名を圧縮して作るようにも読めますね(私自身はIDの様な一意になる数字のつもりで書いていました)。誤解をまねく表現でどうもすみません。
  • id:k2017
    圧縮の必要なし=圧縮する方法を考える必要なし(ここで質問をする意味なし)という意味で書きました。書き方がわるくてすみません。i_kumagoroさんの書いてあることは理解できてましたよ。
  • id:Chiether
    今日、ふと仕事場で頭を過ぎった事を。
    只今高熱に苛まれていますので、走り書きメモ程度に。

    連想配列の方がいいのか……define()の方がいいのか。
    でもget_defined_constantsあたりで取得できるあたり
    パフォーマンスは変わらないのかもしれない。
    むしろdefinedする必要があるから不便で効率悪いかも。

    if( $key == "りんご" ) $val="apple";
    な関数でも用意しておいて、 PHPA とか APC あたりでキャッシュ化した方がいいのか……。

    データ量次第で判断変わるから、いろいろ試してみてください。
  • id:zebevogue
    どのように実装するかは本人次第ですが、
    伝わってないようなので補足します。

    「長」から「短」への一意の重複しない(人の手が不必要で簡易な)方法を示しました。
    連想配列は作り手の恣意的な名前が入る上に
    >キーは数十万件になり
    との事で、重複しないと確定させる事が困難になります。

    その上で、他の方が書かれているDB・ファイル等の方法を使って「短」から「長」への方法を示したまでです。

    他の方へのコメントもそうですが、回答した方への配慮が欠けているように見受けられます。
  • id:k2017
    いつも変なコメント(ポイント狙い)がたくさん付くのであえて厳しめにコメントを書いています。次からは注意して書くようにします。申し訳ありません。


    > Chietherさん

    ありがとうございます。こちらでも色々ためしてみます。
  • id:i_kumagoro
    zebevogueさんへ。
    ハッシュ関数は『「長」から「短」への一意の重複しない』を満たしません。数十万件程度では確率的にはかなり低いですが、重複する可能性があります。

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

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

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

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