5

短いバージョン:衝突を最小限に抑えて、任意の文字列を6桁の数字に変換するにはどうすればよいですか?

ロングバージョン:

私はISBNのない本がたくさんある小さな図書館で働いています。これらは通常、ISBNを最初から入手したことのない小さな出版社からの古い絶版タイトルであり、バーコードスキャンとローンを支援するために偽のISBNを生成したいと思います。

技術的には、実際のISBNは営利団体によって管理されていますが、この形式を使用して、実際の発行元に属さない番号を割り当てることができます(したがって、衝突を引き起こすことはありません)。

形式は次のとおりです。

978-0-01-######-?

000000から999999までの6桁の数字を使用できますか?最後にチェックサムです。

このスキームでは、衝突の可能性を最小限に抑えて、任意の本のタイトルを6桁の数字に変えることができますか?

4

2 に答える 2

1

コード スニペットを使用して固定長のハッシュを作成し、 ISBN-13 チェックサムを計算した後、機能しているように見える非常に醜い C# コードを作成することができました。任意の文字列を取り、それを有効な (ただし偽の) ISBN-13 に変換します。

       public int GetStableHash(string s)
       {
           uint hash = 0;
           // if you care this can be done much faster with unsafe 
           // using fixed char* reinterpreted as a byte*
           foreach (byte b in System.Text.Encoding.Unicode.GetBytes(s))
           {   
               hash += b;
               hash += (hash << 10);
               hash ^= (hash >> 6);    
           }
           // final avalanche
           hash += (hash << 3);
           hash ^= (hash >> 11);
           hash += (hash << 15);
           // helpfully we only want positive integer < MUST_BE_LESS_THAN
           // so simple truncate cast is ok if not perfect
           return (int)(hash % MUST_BE_LESS_THAN);
       }

       public int CalculateChecksumDigit(ulong n)
       {
           string sTemp = n.ToString();
           int iSum = 0;
           int iDigit = 0;

           // Calculate the checksum digit here.
           for (int i = sTemp.Length; i >= 1; i--)
           {
               iDigit = Convert.ToInt32(sTemp.Substring(i - 1, 1));
               // This appears to be backwards but the 
               // EAN-13 checksum must be calculated
               // this way to be compatible with UPC-A.
               if (i % 2 == 0)
               { // odd  
                   iSum += iDigit * 3;
               }
               else
               { // even
                   iSum += iDigit * 1;
               }
           }
           return (10 - (iSum % 10)) % 10;
       }


       private void generateISBN()
       {
           string titlehash = GetStableHash(BookTitle.Text).ToString("D6");
           string fakeisbn = "978001" + titlehash;
           string check = CalculateChecksumDigit(Convert.ToUInt64(fakeisbn)).ToString();

            SixDigitID.Text = fakeisbn + check;
       }
于 2012-10-11T10:16:08.257 に答える
0

6 桁では、約 1,000 万の可能な値が可能であり、ほとんどの内部使用には十分なはずです。6 桁のチェックサムは衝突の可能性が比較的高いため、この場合は代わりにシーケンスを使用します。

したがって、すべての文字列をハッシュに挿入し、ソート後またはソートせずにインデックス番号を ISBN として使用できます。
これにより、競合はほとんど発生しなくなりますが、将来の競合を回避するために「割り当てられた」ISBN の数を保持し、既にストアにあるタイトルのリストを保持する必要がありますが、とにかく保持したい情報です.

もう 1 つのオプションは、ISBN 標準を破り、16 進数/uuencode バーコードを使用することです。これにより、可能な範囲が、切り捨てられた暗号化ハッシュで機能 するポイントまで増加する可能性があります。

古い本のタイトルを扱っているため、いくつかのエディションで大文字と句読点が異なる可能性があるため、比較の前に句読点、重複した空白を取り除き、すべてを小文字に変換して、文字列が異なる (異なる版に異なる ISBN を持たせたい場合を除き、この段落は無視してかまいません)。

于 2012-10-11T08:08:10.957 に答える