मुझे .NET में एक अद्वितीय पहचानकर्ता की आवश्यकता है (GUID का उपयोग नहीं कर सकते क्योंकि यह इस मामले के लिए बहुत लंबा है)।
क्या लोग सोचते हैं कि यहाँ उपयोग किया जाने वाला एल्गोरिदम एक अच्छा उम्मीदवार है या आपके पास कोई अन्य सुझाव है?
मुझे .NET में एक अद्वितीय पहचानकर्ता की आवश्यकता है (GUID का उपयोग नहीं कर सकते क्योंकि यह इस मामले के लिए बहुत लंबा है)।
क्या लोग सोचते हैं कि यहाँ उपयोग किया जाने वाला एल्गोरिदम एक अच्छा उम्मीदवार है या आपके पास कोई अन्य सुझाव है?
जवाबों:
यह एक अच्छा एक है - http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp.aspx
और यहाँ भी YouTube की तरह GUID है
आप Base64 का उपयोग कर सकते हैं:
string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
यह E1HKfn68Pkms5zsZsvKONw == जैसी स्ट्रिंग उत्पन्न करता है। चूंकि एक GUID हमेशा 128 बिट्स होता है, आप == को छोड़ सकते हैं, जो आपको पता है कि हमेशा अंत में मौजूद रहेगा और इससे आपको 22 अक्षर का स्ट्रिंग मिलेगा। हालांकि यह YouTube जितना छोटा नहीं है।
मैं डोर कोहेन के समान दृष्टिकोण का उपयोग करता हूं लेकिन कुछ विशेष पात्रों को हटा रहा हूं:
var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
यह सिर्फ अल्फ़ान्यूमेरिक वर्णों का उत्पादन करेगा। यूआईडी की हमेशा एक ही लंबाई की गारंटी नहीं होती है। यहाँ एक नमूना रन है:
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");
एक आधारभूत तिथि (जो इस मामले में पहली जनवरी 2016 है) रखें, जब से आप इन आईडी का निर्माण शुरू करेंगे। इससे आपकी id छोटी हो जाएगी।
उत्पन्न संख्या: 3af3c14996e54
milliseconds
हमेशा उस DateTime
वस्तु के लिए 0 है
सरल प्रयोग करने योग्य पैकेज। मैं अस्थायी अनुरोध आईडी जनरेटर के लिए इसका इस्तेमाल करता हूं।
https://www.nuget.org/packages/shortid
https://github.com/bolorundurowb/shortid
उपयोग System.Random
string id = ShortId.Generate();
// id = KXTR_VzGVUoOY
(जीथूब पेज से)
यदि आप यह निर्दिष्ट करके आईडी के प्रकार को नियंत्रित करना चाहते हैं कि क्या आप संख्या, विशेष वर्ण और लंबाई चाहते हैं, तो जेनरेट विधि को कॉल करें और तीन पैरामीटर पास करें, पहला बूलियन यह कहते हुए कि क्या आप संख्या चाहते हैं, दूसरा बूलियन यह कहते हुए कि क्या आप चाहते हैं विशेष वर्ण, अंतिम संख्या आपकी लंबाई की प्राथमिकता को दर्शाती है।
string id = ShortId.Generate(true, false, 12);
// id = VvoCDPazES_w
जहां तक मुझे पता है, बस एक GUID के एक हिस्से को अलग करना अद्वितीय होने की गारंटी नहीं है - वास्तव में, यह अद्वितीय होने से बहुत दूर है।
सबसे छोटी चीज जो मुझे पता है कि वैश्विक विशिष्टता की गारंटी देता है जेफ एटवुड द्वारा इस ब्लॉग पोस्ट में चित्रित किया गया है । लिंक किए गए पोस्ट में, वह एक GUID को छोटा करने के कई तरीकों पर चर्चा करता है, और अंत में इसे Ascii85 एन्कोडिंग के माध्यम से 20 बाइट्स तक ले जाता है ।
हालाँकि, अगर आपको किसी ऐसे समाधान की आवश्यकता है जो अब 15 बाइट्स से अधिक नहीं है, तो मुझे डर है कि आपके पास कोई ऐसी चीज़ का उपयोग करने के अलावा और कोई विकल्प नहीं है जो विश्व स्तर पर अद्वितीय होने की गारंटी नहीं है।
एक डेटाबेस में पहचान का मूल्य अद्वितीय होना चाहिए, लेकिन आपको सीमाओं के बारे में पता होना चाहिए ... उदाहरण के लिए, यह थोक डेटा आवेषण मूल रूप से असंभव बनाता है जो आपको धीमा कर देगा यदि आप बहुत बड़ी संख्या में रिकॉर्ड के साथ काम कर रहे हैं।
आप दिनांक / समय मान का उपयोग करने में भी सक्षम हो सकते हैं। मैंने कई डेटाबेस देखे हैं जहां वे PK होने के लिए दिनांक / समय का उपयोग करते हैं, और जब तक यह सुपर क्लीन नहीं होता है - यह काम करता है। यदि आप आवेषण को नियंत्रित करते हैं, तो आप प्रभावी रूप से गारंटी दे सकते हैं कि मूल्य कोड में अद्वितीय होंगे।
अपने स्थानीय एप्लिकेशन के लिए मैं इस समय आधारित दृष्टिकोण का उपयोग कर रहा हूं:
/// <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;
}
यहाँ मेरा समाधान, संगामिति के लिए सुरक्षित नहीं है, 1000 GUID प्रति सेकंड और थ्रेड सुरक्षित नहीं है।
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;
}
कोड अनुकूलित नहीं है, बस नमूना!।
UtcNow
प्रत्येक मिलीसेकंड के लिए एक अद्वितीय टिक मूल्य देता है: टिप्पणियों के अनुसार , संकल्प सिस्टम टाइमर पर निर्भर करता है। इसके अतिरिक्त, आप बेहतर सुनिश्चित करेंगे कि सिस्टम घड़ी पिछड़े नहीं बदले! (चूंकि user13971889 के जवाब ने इस सवाल को मेरे फ़ीड के शीर्ष पर पहुंचा दिया, और मैंने उस उत्तर की आलोचना की, मुझे लगता है कि मुझे उस आलोचना को यहाँ दोहराना चाहिए।)
यदि आपके ऐप में कुछ MILLIION लोग नहीं हैं, तो SAME MILLISECOND पर उस छोटी सी अनोखी स्ट्रिंग का उपयोग करके, आप नीचे दिए गए फ़ंक्शन का उपयोग करने के बारे में सोच सकते हैं।
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());
}
अगर आप को अगले 99 साल में अपने ऐप का उपयोग करने की आवश्यकता है तो yyyy को yy में बदलें।
अद्यतन 20160511 : सही रैंडम फ़ंक्शन
- लॉक ऑब्जेक्ट जोड़ें
- रैंडमस्ट्रीमिंग फ़ंक्शन रेफ से रैंडम वेरिएबल को स्थानांतरित करें
lock
यह है कि आप उसी Random
उदाहरण का फिर से उपयोग कर सकते हैं । मुझे लगता है कि आप उस लाइन को हटाना भूल गए!
मुझे पता है कि यह पोस्ट की तारीख से काफी दूर है ... :)
मेरे पास एक जनरेटर है जो केवल 9 हेक्सा वर्णों का उत्पादन करता है , जैसे: 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");
}
}
@ Dorcohen के जवाब और @ pootzko की टिप्पणी के आधार पर। आप इसका उपयोग कर सकते हैं। यह तार के ऊपर सुरक्षित है।
var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
Jzhw2oVozkSNa2IkyK4ilA2
या अपने आप को dotnetfiddle.net/VIrZ8j
कुछ अन्य लोगों के आधार पर, यहां मेरा समाधान है जो एक अलग एन्कोडेड गाइड प्रदान करता है जो कि URL (और डॉकर) सुरक्षित है और इसमें कोई अंतर नहीं है:
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("=", "").Replace("+", "-").Replace("/", "_");
उदाहरण आउटपुट हैं:
BcfttHA780qMdHSxSBoZFA
_4p5srPgOE2f25T_UnoGLw
H9xR_zdfm0y-zYjdR3NOig
C # में एक long
मान 64 बिट्स का है, जिसे अगर Base64 के साथ एनकोड किया गया तो 1 पैडिंग सहित 12 अक्षर होंगे =
। यदि हम पैडिंग को ट्रिम करते हैं =
, तो 11 वर्ण होंगे।
एक पागल विचार यहाँ है कि हम यूनिक्स एपोच के संयोजन और एक युग मूल्य के लिए एक काउंटर का उपयोग मूल्य बनाने के लिए कर सकते हैं long
। यूनिक्स काल सी में # DateTimeOffset.ToUnixEpochMilliseconds
में है long
प्रारूप है, लेकिन 8 बाइट्स के पहले 2 बाइट्स हमेशा 0 कर रहे हैं, क्योंकि अन्यथा दिनांक समय मूल्य अधिकतम दिनांक समय मूल्य से अधिक हो जाएगा। ताकि हमें जगह देने के लिए 2 बाइट्स मिलेushort
काउंटर ।
इसलिए, कुल मिलाकर, जब तक आईडी पीढ़ी की संख्या 65536 प्रति मिलीसेकंड से अधिक नहीं होती, हमारे पास एक अद्वितीय आईडी हो सकती है:
// 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)
}
प्रयोग
Guid.NewGuid().ToTinyUuid()
यह रॉकेट विज्ञान नहीं है कि मैं इसे वापस बदल सकूं, इसलिए मैं आपको छोड़ दूंगा।
यदि आपको स्ट्रिंग का उपयोग करने की आवश्यकता नहीं है, तो आप निम्नलिखित का उपयोग कर सकते हैं:
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());
}
यह मार्गदर्शिका को 8 वर्ण स्ट्रिंग की तरह परिवर्तित कर देगा:
{b77a49a5-182b-42fa-83a9-824ebd6ab58d} -> "" a a ᠫ a a a a a "
{c5f8f7f5-8a7c-4511-b667-8ad36b446617} -> "" - f f f f f f f "
एक यादृच्छिक और छोटी अनोखी आईडी बनाने के लिए यहां मेरी छोटी विधि है। सुरक्षित यादृच्छिक संख्या पीढ़ी के लिए एक क्रिप्टोग्राफ़िक आरएनजी का उपयोग करता है। chars
स्ट्रिंग के लिए आपको जो भी वर्ण चाहिए उन्हें जोड़ें ।
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);
}
अक्षरों को खोना नहीं (+ / -) और यदि आप अपने गाइड का उपयोग url में करना चाहते हैं, तो उसे आधार ३२ में बदलना चाहिए
10 000 000 के लिए कोई डुप्लिकेट कुंजी नहीं
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;
}
आप निम्नलिखित पुस्तकालय के साथ कोशिश कर सकते हैं:
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
प्रत्येक मिलीसेकंड के लिए एक अद्वितीय टिक मूल्य देता है: टिप्पणियों के अनुसार , संकल्प सिस्टम टाइमर पर निर्भर करता है। इसके अतिरिक्त, आप बेहतर सुनिश्चित करेंगे कि सिस्टम घड़ी पिछड़े नहीं बदले! (ur3an0 का जवाब भी इन मुद्दों की है।)
आप उपयोग कर सकते हैं
code = await UserManager.GenerateChangePhoneNumberTokenAsync(input.UserId, input.MobileNumber);
6
केवल इसके अच्छे चरित्र 599527
,143354
और जब उपयोगकर्ता इसे सरल रूप से बताता है
var result = await UserManager.VerifyChangePhoneNumberTokenAsync(input.UserId, input.Token, input.MobileNumber);
आशा है कि यह आपकी मदद करेगा
Guid.NewGuid().ToString().Split('-').First()