Saya membutuhkan pengenal unik di .NET (tidak dapat menggunakan GUID karena terlalu panjang untuk kasus ini).
Apakah orang-orang berpikir bahwa algoritme yang digunakan di sini adalah kandidat yang bagus atau Anda punya saran lain?
Saya membutuhkan pengenal unik di .NET (tidak dapat menggunakan GUID karena terlalu panjang untuk kasus ini).
Apakah orang-orang berpikir bahwa algoritme yang digunakan di sini adalah kandidat yang bagus atau Anda punya saran lain?
Jawaban:
Yang ini bagus - http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp.aspx
dan juga di sini GUID seperti YouTube
Anda bisa menggunakan Base64:
string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
Itu menghasilkan string seperti E1HKfn68Pkms5zsZsvKONw ==. Karena GUID selalu 128 bit, Anda dapat menghilangkan == yang Anda tahu akan selalu ada di akhir dan itu akan memberi Anda 22 karakter string. Ini tidak sesingkat YouTube.
Saya menggunakan pendekatan yang mirip dengan Dor Cohen tetapi menghapus beberapa karakter khusus:
var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
Ini hanya akan menampilkan karakter alfanumerik. UID tidak dijamin memiliki panjang yang selalu sama. Berikut adalah contoh yang dijalankan:
vmKo0zws8k28fR4V4Hgmw
TKbhS0G2V0KqtpHOU8e6Ug
rfDi1RdO0aQHTosh9dVvw
3jhCD75fUWjQek8XRmMg
CQUg1lXIXkWG8KDFy7z6Ow
bvyxW5aj10OmKA5KMhppw
pIMK8eq5kyvLK67xtsIDg
VX4oljGWpkSQGR2OvGoOQ
NOHBjUUHv06yIc7EvotRg
iMniAuUG9kiGLwBtBQByfg
var ticks = new DateTime(2016,1,1).Ticks;
var ans = DateTime.Now.Ticks - ticks;
var uniqueId = ans.ToString("x");
Pertahankan tanggal dasar (dalam hal ini adalah 1 Jan 2016) sejak Anda mulai membuat ID ini. Ini akan membuat id Anda lebih kecil.
Nomor yang Dihasilkan: 3af3c14996e54
milliseconds
selalu 0 untuk DateTime
objek itu
Paket sederhana yang dapat digunakan. Saya menggunakannya untuk generator id permintaan temporal.
https://www.nuget.org/packages/shortid
https://github.com/bolorundurowb/shortid
Kegunaan System.Random
string id = ShortId.Generate();
// id = KXTR_VzGVUoOY
(dari halaman github)
Jika Anda ingin mengontrol tipe id yang dihasilkan dengan menentukan apakah Anda menginginkan angka, karakter khusus dan panjangnya, panggil metode Generate dan berikan tiga parameter, yang pertama adalah boolean yang menyatakan apakah Anda menginginkan angka, yang kedua adalah boolean yang menyatakan apakah Anda mau karakter khusus, angka terakhir yang menunjukkan preferensi panjang Anda.
string id = ShortId.Generate(true, false, 12);
// id = VvoCDPazES_w
Sejauh yang saya tahu, hanya melepas sebagian GUID tidak dijamin unik - pada kenyataannya, itu jauh dari unik.
Hal terpendek yang saya tahu yang menjamin keunikan global ditampilkan dalam posting blog ini oleh Jeff Atwood . Dalam posting tertaut, dia membahas berbagai cara untuk mempersingkat GUID, dan pada akhirnya menurunkannya menjadi 20 byte melalui pengkodean Ascii85 .
Namun, jika Anda benar-benar membutuhkan solusi yang tidak lebih dari 15 byte, saya khawatir Anda tidak punya pilihan lain selain menggunakan sesuatu yang tidak dijamin unik secara global.
Nilai IDENTITAS harus unik dalam database, tetapi Anda harus menyadari keterbatasannya ... misalnya, ini membuat penyisipan data massal pada dasarnya tidak mungkin yang akan memperlambat Anda jika Anda bekerja dengan record dalam jumlah yang sangat besar.
Anda juga mungkin dapat menggunakan nilai tanggal / waktu. Saya telah melihat beberapa database di mana mereka menggunakan tanggal / waktu untuk menjadi PK, dan meskipun tidak super bersih - itu berhasil. Jika Anda mengontrol sisipan, Anda dapat secara efektif menjamin bahwa nilainya akan unik dalam kode.
Untuk aplikasi lokal saya, saya menggunakan pendekatan berbasis waktu ini:
/// <summary>
/// Returns all ticks, milliseconds or seconds since 1970.
///
/// 1 tick = 100 nanoseconds
///
/// Samples:
///
/// Return unit value decimal length value hex length
/// --------------------------------------------------------------------------
/// ticks 14094017407993061 17 3212786FA068F0 14
/// milliseconds 1409397614940 13 148271D0BC5 11
/// seconds 1409397492 10 5401D2AE 8
///
/// </summary>
public static string TickIdGet(bool getSecondsNotTicks, bool getMillisecondsNotTicks, bool getHexValue)
{
string id = string.Empty;
DateTime historicalDate = new DateTime(1970, 1, 1, 0, 0, 0);
if (getSecondsNotTicks || getMillisecondsNotTicks)
{
TimeSpan spanTillNow = DateTime.UtcNow.Subtract(historicalDate);
if (getSecondsNotTicks)
id = String.Format("{0:0}", spanTillNow.TotalSeconds);
else
id = String.Format("{0:0}", spanTillNow.TotalMilliseconds);
}
else
{
long ticksTillNow = DateTime.UtcNow.Ticks - historicalDate.Ticks;
id = ticksTillNow.ToString();
}
if (getHexValue)
id = long.Parse(id).ToString("X");
return id;
}
di sini solusi saya, tidak aman untuk konkurensi, tidak lebih dari 1000 GUID per detik dan aman utas.
public static class Extensors
{
private static object _lockGuidObject;
public static string GetGuid()
{
if (_lockGuidObject == null)
_lockGuidObject = new object();
lock (_lockGuidObject)
{
Thread.Sleep(1);
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var epochLong = Convert.ToInt64((DateTime.UtcNow - epoch).TotalMilliseconds);
return epochLong.DecimalToArbitrarySystem(36);
}
}
/// <summary>
/// Converts the given decimal number to the numeral system with the
/// specified radix (in the range [2, 36]).
/// </summary>
/// <param name="decimalNumber">The number to convert.</param>
/// <param name="radix">The radix of the destination numeral system (in the range [2, 36]).</param>
/// <returns></returns>
public static string DecimalToArbitrarySystem(this long decimalNumber, int radix)
{
const int BitsInLong = 64;
const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (radix < 2 || radix > Digits.Length)
throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString());
if (decimalNumber == 0)
return "0";
int index = BitsInLong - 1;
long currentNumber = Math.Abs(decimalNumber);
char[] charArray = new char[BitsInLong];
while (currentNumber != 0)
{
int remainder = (int)(currentNumber % radix);
charArray[index--] = Digits[remainder];
currentNumber = currentNumber / radix;
}
string result = new String(charArray, index + 1, BitsInLong - index - 1);
if (decimalNumber < 0)
{
result = "-" + result;
}
return result;
}
kode tidak dioptimalkan, cukup sampel !.
UtcNow
mengembalikan nilai centang unik untuk setiap milidetik: menurut komentar , resolusinya bergantung pada timer sistem. Selain itu, Anda sebaiknya memastikan jam sistem tidak berubah mundur! (Karena jawaban pengguna13971889 menabrak pertanyaan ini ke bagian atas umpan saya, dan saya mengkritik jawaban itu, saya pikir saya harus mengulangi kritik itu di sini.)
Jika aplikasi Anda tidak memiliki beberapa JUTA orang, menggunakan yang menghasilkan string unik pendek di SAMA MILLISECOND, Anda dapat berpikir tentang menggunakan fungsi di bawah ini.
private static readonly Object obj = new Object();
private static readonly Random random = new Random();
private string CreateShortUniqueString()
{
string strDate = DateTime.Now.ToString("yyyyMMddhhmmssfff");
string randomString ;
lock (obj)
{
randomString = RandomString(3);
}
return strDate + randomString; // 16 charater
}
private string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy";
var random = new Random();
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
ubah yyyy menjadi yy jika Anda hanya perlu menggunakan aplikasi Anda dalam 99 tahun ke depan.
Pembaruan 20160511 : Benar Fungsi Acak
- Tambahkan objek Kunci
- Pindahkan variabel acak dari fungsi RandomString
Ref
lock
adalah untuk memungkinkan Anda menggunakan kembali Random
instance yang sama . Saya pikir Anda lupa menghapus baris itu!
Saya tahu ini cukup jauh dari tanggal diposting ... :)
Saya memiliki generator yang hanya menghasilkan 9 karakter Hexa , misalnya: C9D6F7FF3, C9D6FB52C
public class SlimHexIdGenerator : IIdGenerator
{
private readonly DateTime _baseDate = new DateTime(2016, 1, 1);
private readonly IDictionary<long, IList<long>> _cache = new Dictionary<long, IList<long>>();
public string NewId()
{
var now = DateTime.Now.ToString("HHmmssfff");
var daysDiff = (DateTime.Today - _baseDate).Days;
var current = long.Parse(string.Format("{0}{1}", daysDiff, now));
return IdGeneratorHelper.NewId(_cache, current);
}
}
static class IdGeneratorHelper
{
public static string NewId(IDictionary<long, IList<long>> cache, long current)
{
if (cache.Any() && cache.Keys.Max() < current)
{
cache.Clear();
}
if (!cache.Any())
{
cache.Add(current, new List<long>());
}
string secondPart;
if (cache[current].Any())
{
var maxValue = cache[current].Max();
cache[current].Add(maxValue + 1);
secondPart = maxValue.ToString(CultureInfo.InvariantCulture);
}
else
{
cache[current].Add(0);
secondPart = string.Empty;
}
var nextValueFormatted = string.Format("{0}{1}", current, secondPart);
return UInt64.Parse(nextValueFormatted).ToString("X");
}
}
Berdasarkan jawaban @ dorcohen dan komentar @pootzko. Anda bisa menggunakan ini. Aman di atas kabel.
var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
Jzhw2oVozkSNa2IkyK4ilA2
atau coba sendiri di dotnetfiddle.net/VIrZ8j
Berdasarkan beberapa lainnya, berikut adalah solusi saya yang menyediakan panduan yang dikodekan berbeda yaitu URL (dan Docker) aman dan tidak kehilangan informasi apa pun:
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("=", "").Replace("+", "-").Replace("/", "_");
Contoh keluarannya adalah:
BcfttHA780qMdHSxSBoZFA
_4p5srPgOE2f25T_UnoGLw
H9xR_zdfm0y-zYjdR3NOig
Dalam C # sebuah long
nilai memiliki 64 bit, yang jika dikodekan dengan Base64 akan ada 12 karakter, termasuk 1 padding =
. Jika padding kita rapikan =
, akan ada 11 karakter.
Satu ide gila di sini adalah kita bisa menggunakan kombinasi Unix Epoch dan penghitung untuk satu nilai epoch untuk membentuk long
nilai. Unix Epoch dalam C # DateTimeOffset.ToUnixEpochMilliseconds
dalam long
format, tetapi 2 byte pertama dari 8 byte selalu 0, karena jika tidak, nilai waktu tanggal akan lebih besar dari nilai waktu tanggal maksimum. Jadi itu memberi kita 2 byte untuk menempatkan ushort
penghitung.
Jadi, secara total, selama jumlah pembuatan ID tidak melebihi 65536 per milidetik, kita dapat memiliki ID unik:
// This is the counter for current epoch. Counter should reset in next millisecond
ushort currentCounter = 123;
var epoch = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// Because epoch is 64bit long, so we should have 8 bytes
var epochBytes = BitConverter.GetBytes(epoch);
if (BitConverter.IsLittleEndian)
{
// Use big endian
epochBytes = epochBytes.Reverse().ToArray();
}
// The first two bytes are always 0, because if not, the DateTime.UtcNow is greater
// than DateTime.Max, which is not possible
var counterBytes = BitConverter.GetBytes(currentCounter);
if (BitConverter.IsLittleEndian)
{
// Use big endian
counterBytes = counterBytes.Reverse().ToArray();
}
// Copy counter bytes to the first 2 bytes of the epoch bytes
Array.Copy(counterBytes, 0, epochBytes, 0, 2);
// Encode the byte array and trim padding '='
// e.g. AAsBcTCCVlg
var shortUid = Convert.ToBase64String(epochBytes).TrimEnd('=');
public static string ToTinyUuid(this Guid guid)
{
return Convert.ToBase64String(guid.ToByteArray())[0..^2] // remove trailing == padding
.Replace('+', '-') // escape (for filepath)
.Replace('/', '_'); // escape (for filepath)
}
Pemakaian
Guid.NewGuid().ToTinyUuid()
Bukan ilmu roket untuk mengubahnya kembali, jadi saya akan meninggalkan Anda sebanyak itu.
Jika Anda tidak perlu mengetikkan string, Anda dapat menggunakan yang berikut ini:
static class GuidConverter
{
public static string GuidToString(Guid g)
{
var bytes = g.ToByteArray();
var sb = new StringBuilder();
for (var j = 0; j < bytes.Length; j++)
{
var c = BitConverter.ToChar(bytes, j);
sb.Append(c);
j++;
}
return sb.ToString();
}
public static Guid StringToGuid(string s)
=> new Guid(s.SelectMany(BitConverter.GetBytes).ToArray());
}
Ini akan mengubah Panduan menjadi String 8 karakter seperti ini:
{b77a49a5-182b-42fa-83a9-824ebd6ab58d} -> "䦥 띺 ᠫ 䋺 ꦃ 亂 檽 趵"
{c5f8f7f5-8a7c-4511-b667-8ad36b446617} -> " 엸 詼 䔑 架 펊 䑫 ᝦ"
Inilah metode kecil saya untuk menghasilkan id unik acak dan pendek. Menggunakan rng kriptografi untuk pembuatan nomor acak yang aman. Tambahkan karakter apa pun yang Anda butuhkan ke chars
string.
private string GenerateRandomId(int length)
{
char[] stringChars = new char[length];
byte[] randomBytes = new byte[length];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomBytes);
}
string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[randomBytes[i] % chars.Length];
}
return new string(stringChars);
}
untuk tidak kehilangan karakter (+ / -) dan jika Anda ingin menggunakan guid Anda di url, itu harus diubah menjadi base32
untuk 10.000.000 tidak ada kunci duplikat
public static List<string> guids = new List<string>();
static void Main(string[] args)
{
for (int i = 0; i < 10000000; i++)
{
var guid = Guid.NewGuid();
string encoded = BytesToBase32(guid.ToByteArray());
guids.Add(encoded);
Console.Write(".");
}
var result = guids.GroupBy(x => x)
.Where(group => group.Count() > 1)
.Select(group => group.Key);
foreach (var res in result)
Console.WriteLine($"Duplicate {res}");
Console.WriteLine($"*********** end **************");
Console.ReadLine();
}
public static string BytesToBase32(byte[] bytes)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
string output = "";
for (int bitIndex = 0; bitIndex < bytes.Length * 8; bitIndex += 5)
{
int dualbyte = bytes[bitIndex / 8] << 8;
if (bitIndex / 8 + 1 < bytes.Length)
dualbyte |= bytes[bitIndex / 8 + 1];
dualbyte = 0x1f & (dualbyte >> (16 - bitIndex % 8 - 5));
output += alphabet[dualbyte];
}
return output;
}
Anda dapat mencoba dengan perpustakaan berikut:
private static readonly object _getUniqueIdLock = new object();
public static string GetUniqueId()
{
lock(_getUniqueIdLock)
{
System.Threading.Thread.Sleep(1);
return DateTime.UtcNow.Ticks.ToString("X");
}
}
UtcNow
mengembalikan nilai centang unik untuk setiap milidetik: menurut komentar , resolusinya bergantung pada timer sistem. Selain itu, Anda sebaiknya memastikan jam sistem tidak berubah mundur! (Jawaban ur3an0 juga memiliki masalah ini.)
kamu bisa memakai
code = await UserManager.GenerateChangePhoneNumberTokenAsync(input.UserId, input.MobileNumber);
nya 6
karakter bagus saja, 599527
,143354
dan saat pengguna melakukannya dengan mudah
var result = await UserManager.VerifyChangePhoneNumberTokenAsync(input.UserId, input.Token, input.MobileNumber);
semoga ini membantu Anda
Guid.NewGuid().ToString().Split('-').First()