7

I'm looking to use some sort of unique identifier within a .resx file but it does not allow the key to begin with a number. Rather than cycling through GUIDs until I get one that starts with a letter, I'm wondering if there's an alternative UID type that either does not contain numbers or would otherwise meet this requirement.

Any thoughts?

Sinaesthetic
  • 11,426
  • 28
  • 107
  • 176

7 Answers7

14

If you just want to create a Guid that starts with a letter, you could do something like this:

var b = Guid.NewGuid().ToByteArray();
b[3] |= 0xF0;
return new Guid(b);

This will always generate a GUID that starts with the hex digit F.

To create a Guid that doesn't contain any numbers you could use something like this:

return new Guid(Guid.NewGuid().ToByteArray()
    .Select(b => (byte)(((b % 16) < 10 ? 0xA : b) | 
                        (((b >> 4) < 10 ? 0xA : (b >> 4)) << 4)))
    .ToArray());

This will test each hex digit (two per byte) and coerce it to A if it's less than A.


Both the above solutions generate real Guid objects, although the added restrictions do decrease the uniqueness of the resulting GUIDs to some degree (far more so in the second example). If you don't care about the output being actual GUIDs, you can simply remap the hex digits to something else and return the result a string, as others have suggested. FWIW, here's the shortest solution I can think of:

return String.Concat(Guid.NewGuid().ToString("N").Select(c => (char)(c + 17)));

This maps the hex digits 0 through 9 to the characters A through J, and the hex digits A - F to the characters r through w. It also generates a string without any hyphens. It For example:

Before: e58d0f329a2f4615b922ecf53dcd090a
After:  vFIuAwDCJrCwEGBFsJCCvtwFDutuAJAr

Of course, you could convert this to all upper or lower case if you don't like the mixed case here.

p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • 2
    @HamletHakobyan: Even GUIDs fresh from `Guid.NewGuid`, with no mangling at all, aren't guaranteed to be unique. There's just a very, very, very high probability. – cHao Sep 05 '13 at 21:00
  • @HamletHakobyan It's certainly not as unique as regular Guid's because you're restricting the GUIDs to only a smaller subset of Guids. Even GUIDs are not *guaranteed* to be unique, only so unique that you wouldn't reasonable expect to find a duplicate within the lifetime of the universe. How unique you *need* them to be depends on the application. – p.s.w.g Sep 05 '13 at 21:03
  • I will say, though, the edit (about coercing all digits to letters) does blow the likelihood of uniqueness all to hell. It's now well under 1 in 6^32. – cHao Sep 05 '13 at 21:06
  • @HamletHakobyan [How unique is UUID?](http://stackoverflow.com/questions/1155008/how-unique-is-uuid?rq=1) – p.s.w.g Sep 05 '13 at 21:06
  • @HamletHakobyan: http://msdn.microsoft.com/en-us/library/system.guid.aspx explicitly states: "Such an identifier has a very low probability of being duplicated." – cHao Sep 05 '13 at 21:08
  • @cHao Yes. Do you know what mean 2^122? – Hamlet Hakobyan Sep 05 '13 at 21:12
  • 2
    @Hamlet: Among other things, it means "a finite number". The fact is that they're not guaranteed to be unique. They're close enough that you can count on uniqueness in just about all cases...but if you need to be absolutely sure, you need to keep track of what GUIDs have already been used. Because if duplication is a life or death matter, 1/2^122 is way bigger than 0. – cHao Sep 05 '13 at 21:18
  • What if one wants to generate a 5 or 8 digit unique number. That number must contains only numeric digits and no alphabets. Is it possible? If yes, please provide some information on that. – phougatv Jul 01 '15 at 11:20
  • @barnes In that case it seems easy just to use a [`Random`](https://msdn.microsoft.com/en-us/library/System.Random(v=vs.110).aspx) to generate a number between in that range. e.g. `var rand = new Random(); var result = rand.Next(10000, 100000000)`. – p.s.w.g Jul 01 '15 at 11:43
  • Thanks a lot. :) BTW I did figure it out. ;) – phougatv Jul 01 '15 at 13:14
3

How about generating a unique number and then prefixing it with a letter? So instead of

1234

You would use

a1234

As long as the algorithm you choose for the identifier guarantees a unique number, this should work just fine. It will also give you the ability to strip out the prefix and work with the identifier as a number again if need be.

aleppke
  • 496
  • 4
  • 13
2

Assuming that you don't need it to a be valid Guid (you refer to 'some sort of unique identifier'), just create a string based guid (using Guid.NewGuid().ToString()) then map the first digit to a range of suitable letters e.g. 0=G, 1=H, 2=I etc.

Plymouth223
  • 1,905
  • 1
  • 12
  • 22
2

You can write and use a psuedorandom sequence generator. Here's one that gives the basic idea:

class RandomLetterSequence { 
    private static Random r; 
    private static char MinChar = (char) 0x0061; 
    private static char MaxChar = (char) 0x007A; 

    public static string RandomSequence() { 
        return RandomSequence(32);  
    }

    public static string RandomSequence(int length) { 
        if (r == null)
            r = new Random(); 
        var sb = new StringBuilder(); 
        for (int i = length; i >= 0; i--) { 
            sb.Append((char)(r.Next(MinChar, MaxChar))); 
        }
        return sb.ToString();
    }
}

With this implementation, there are 26^32 possible different sequences that are generated that conform to your requirements:

  • Similar to GUIDs in terms of collision rate (infinitesimally small)
  • Contains only letters
jdphenix
  • 15,022
  • 3
  • 41
  • 74
1

Just write your own GUID-like generator, a valid character would be a-z (you can also use A-Z to increase the number of probabilities).

socksocket
  • 4,271
  • 11
  • 45
  • 70
1

Generate the new GUID and just replace the characters 0-9 with characters g-p.

Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
0

@p.s.w.g provided good solution.

You can write his/her recommendations as Extension:

using System;
using System.Linq;

namespace YourApp.Extensions.GuidExtensions
{
    public static class Extension
    {
        public static Guid FirstLetter(this Guid obj)
        {
            var b = obj.ToByteArray();
            b[3] |= 0xF0;
            return new Guid(b);
        }

        public static Guid OnlyLetters(this Guid obj)
        {
            var ba = obj.ToByteArray();
            return new Guid(
                ba.Select(b => (byte)(((b % 16) < 10 ? 0xA : b) |
                                      (((b >> 4) < 10 ? 0xA : (b >> 4)) << 4)))
                  .ToArray()
            );
        }
    }
}

And then use it somewhere in app:

// ...
using YourApp.Extensions.GuidExtensions;
// ...

class SomeClass {
    Guid SomeMethodWithFirstLetter() {
        return Guid.NewGuid().FirstLetter();
    }


    Guid SomeMethodWithOnlyLetters() {
        return Guid.NewGuid().OnlyLetters();
    }
}
merqlove
  • 3,674
  • 1
  • 23
  • 22