Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I always wanted to use randomly generated strings for my resources' IDs, so I could have shorter URLs like this: /user/4jz0k1

But I never did, because I was worried about the random string generation creating actual words, eg: /user/f*cker. This brings two problems: it might be confusing or even offensive for users, and it could mess with the SEO too.

Then I thought all I had to do was to set up a fixed pattern like adding a number every 2 letters. I was very happy with my 'generate_safe_uuid' method, but then I realized it was only better for SEO, and worse for users, because it increased the ratio of actual words being generated, eg: /user/g4yd1ck5

Now I'm thinking I could create a method 'replace_numbers_with_letters', and check that it haven't formed any words against a dictionary or something.

Any other ideas?

ps. As I write this, I also realized that checking for words in more than one language (eg: english and french, spanish, etc) would be a mess, and I'm starting to love numbers-only IDs again.

UPDATE

Some links everyone should read:

http://thedailywtf.com/Articles/The-Automated-Curse-Generator.aspx

http://blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx

share|improve this question
    
Use a hash or checksum? If you prefer to use a random string, theres no rule that you have to use every letter in the alphabet. –  Austin Henley Apr 7 '12 at 16:42
17  
Don't call it a uuid, uuid are universally unique identifiers. Its refers to a specific system of identifiers that you can use. That's not what you are doing here, so don't use that term. –  Winston Ewert Apr 7 '12 at 17:56
3  
I will just leave you with the tale of the Automatic Curse Generator –  Scott Chamberlain Apr 7 '12 at 20:25
1  
@HappyDeveloper, firstly, its not universal. It is specific to your application. Secondly, uuid specifically refers to en.wikipedia.org/wiki/Universally_unique_identifier not any similar scheme that you devise. –  Winston Ewert Apr 7 '12 at 22:36
2  
This is such an incredible waste of braintime. The chances of it actually happening is way too small to be worth even thinking about... –  Michael Borgwardt Apr 8 '12 at 19:55
show 7 more comments

7 Answers

A couple of tips that will lower the chances of inadvertently creating meaningful words:

  • Add some non-alpha, non-numerical characters to the mix, such as "-", "!" or "_".
  • Compose your UUIDs by accumulating sequences of characters (rather than single characters) that are unlikely to occur in real words, such as "zx" or "aa".

This is some C# sample code (using .NET 4):

private string MakeRandomString()  
{  
    var bits = new List<string>()  
    {  
            "a",  
            "b",  
            "c",  
            "d",  
            "e",  
            //keep going with letters.  
            "0",  
            "1",  
            "2",  
            "3",  
            //keep going with numbers.  
            "-",  
            "!",  
            "_",  
            //add some more non-alpha, non-numeric characters.  
            "zx",  
            "aa",  
            "kq",  
            "jr",  
            "yq",  
            //add some more odd combinations to the mix.  
    };  

    StringBuilder sb = new StringBuilder();  
    Random r = new Random();  
    for (int i = 0; i < 8; i++)  
    {  
        sb.Append(bits[r.Next(bits.Count)]);  
    }  

    return sb.ToString();  
}  

This doesn't guarantee that you won't offend anyone, but I agree with @DeadMG that you cannot aim so high.

share|improve this answer
    
problem with non-alphanumeric is that some of them shall not play nice in URIs (leading to escaped character, which are a big no-no in a tiny URL: there's a reason with bit.ly and tinyurl aren't using them). The other issue is that they're less intuitive to user: they aren't easy to, say, write down on a post-it or transmit on the phone (many non-techies have no clue what the name of underscore is, for example). Once again there's a reason why tiny url and bit.ly aren't using them. –  user988052 Apr 8 '12 at 0:14
    
@user988052: Hence some non-alpha, non-numerical characters. It's easy to select a few that are fine for URIs and easy enough for humans. –  CesarGon Apr 8 '12 at 21:05
    
"Hence some non-alpha, non-numerical characters." [sic]... URL shortening services (bit.ly, tinyurl, t.co, goo.gl, etc.) seems to think that zero non-alphanum is better than "some". And I think that the reasons I explained in my previous comments are part of the explanation as to why these services aren't agreeing with your point of view. Now obviously our opinions are differing on the matter and I'll leave you the last word ; ) –  user988052 Apr 8 '12 at 21:59
    
@user988052: I've been using goo.gl for ages and it never had an issue with converting all sorts of non-alpha characters; the only exception being %. You can find this documented in the service's discussion group. Can you provide any reference that backs up your claims? –  CesarGon Apr 9 '12 at 7:58
1  
OP stated he wanted short names and asks for a method to generate these. You suggest "adding son non-alpha, non-numerical characters to the mix" [sic]. So what are you suggesting? That OP first generates "something" and then send this to tinyurl/bit.ly? I think that is not what OP is after. OP wants to directly generate a URL that is relatively "tiny". All I'm saying is that if that's what he's after, then it may be better for him to use an alphanum alphabet, just like tinyurl/bit.ly is doing! Now I'm really off. –  user988052 Apr 10 '12 at 11:03
show 2 more comments

Just create a naughty word list, a letter substitution list, and then if any ID generated is a naughty word, redo it.

For instance (pseudo code)

naughty_words = ["ass", "shit", "boobs"]
substitutions = {
    "4" : "a"
    "1" : "i"
    "3" : "e"
    "7" : "t"
    "5" : "s"
    "0" : "o"
    // etc.
}

function reducestring (str) {
    newstr = ""
    for (character in str) {
        if (substitituions[character]) newstr += substitutions[character]
        else newstr += character
    }
    return tolower(newstr)
}

do {
    new_id_numeric = random_number()
    short_id = compress_to_alphanumeric(new_id_numeric) // 0-9, a-z, A-Z
    // that function should create a base 62 number
} while (!contains(naughty_words, reducestring(short_id))

(You can refer to other short url recommendations like this one for info on base 62 hashing/conversion)

Now you no longer get IDs like a55, sh1t, or "b00bs". Your letter substitution list would only need to contain characters in your naughty words, obviously.

Since no one is going to read "455" as "ass" then you might also want to return str in reducestring if it doesn't contain any letters.

Examples

The graphic-design site Dribbble has its own short string ids for posts. These use 0-9, a-z and A-Z like http://drbl.in/dCWi.

I did some experimenting and there are short ids for at least a few naughty words. I guess we'll see when they get to f, but they aren't there yet.

Granted -- giving a user their own personally-identifying url (/user/whatever) instead of just a post is much worse with naughty words.

share|improve this answer
    
Nice findings, thanks –  HappyDeveloper Apr 8 '12 at 0:05
2  
I once wrote a program that generated passwords for an online service. They were random, but there were a few heuristics that made them sorta pronounceable, so they would be more easily remembered. And these heuristics led to profanity. The solution was as described here: check for vulgar substrings, including those that could be pronounced similarly to vulgar words (e.g. look for FUC and FUK) and regenerate the password. (For giggles, the program wrote the rejected passwords to a separate file.) –  kindall Apr 8 '12 at 2:10
1  
And how on earth are you going to write such a thing for every language? –  DeadMG Apr 8 '12 at 11:20
1  
@DeadMG For the full set of all possible offensive words, this can only make that set smaller. Is your stance really: "because you can't reach 100%, it's automatically not worth doing anything"? –  NickC Apr 8 '12 at 15:00
1  
@JBRWilkinson that doesn't apply because the OP is setting the character set of alphanumeric characters for IDs, right? –  NickC Apr 8 '12 at 20:08
show 2 more comments

Consider using a numeric or hexadecimal key instead. It will save you a lot of trouble compared to writing an i18n-aware profanity filter, and the worst you'll have to worry about is dead beef.

share|improve this answer
1  
+1: I think this is the simplest and safest solution. You can generated a uuid in the form of a number and use a string representation for it (decimal, hexadecimal, octal). –  Giorgio Jun 26 '12 at 19:58
1  
You still have to worry about B16B00B5 :P –  CodesInChaos Jun 4 '13 at 21:51
add comment

You can never prevent an automated system from generating some string that's offensive to a user. For example, in China some numbers are considered unlucky.

All you can really do is tell the user that their ID is random and the contents are irrelevant and if they get /user/fucker then they should just ignore it. These things happen and it's just not technically feasible to avoid it- just like you can never filter profanity.

share|improve this answer
9  
I am not the downvoter, but I feel very strongly that for offensive words you really need to do a much, much, much better than "tell them they should just ignore it". The least you could do is offer some way to change the generated id to one they do find acceptable. –  Marjan Venema Apr 7 '12 at 16:48
4  
I'm not the downvoter either, but I agree with @MarjanVenema, /user/f*cker is not acceptable –  HappyDeveloper Apr 7 '12 at 16:52
    
@HappyDeveloper: As I previously suggested, what are you going to do about it? You can't prevent users from being given IDs that they find offensive. –  DeadMG Apr 7 '12 at 21:58
3  
@DeadMG You can help the situation by preventing a few commonly-offensive cases. I thought the original question made that pretty clear. –  NickC Apr 7 '12 at 23:06
2  
@NickC: The only examples are commonly offensive in English. Do you have any idea what's commonly offensive in Arabic, Portuguese, Chinese, Russian? Not to mention the fact that those languages may have swearwords that take many, many forms. It's easy to special-case the obvious forms of the words from English, but not so easy to do it for everybody. –  DeadMG Apr 8 '12 at 11:14
add comment

There are essentially two strategies that you can employ:

  1. Create a system that won't generate any offensive strings. For example, you can compose your id's only from consonant letters. By leaving out all vowels, you can be sure that your system will never generate any English words, naughty or otherwise.

  2. After generating a completely random id, check to make sure that the new id doesn't include any offensive substrings.

share|improve this answer
    
lythxxrsys yrsystmysshyt rmvyplz lylz. –  CodesInChaos Jun 26 '12 at 19:14
    
@CodeInChaos What point are you trying to make? –  Caleb Jun 26 '12 at 19:19
add comment

In many situations (email spam, ip blocking, etc), a blacklist is a losing game -- you'll never be able to make a "complete" blacklist of every possible bad thing that could ever occur. a b c d e f

Many people use a whitelist of acceptable words and string them together in some random order. (Perhaps with a dash or dot or space between each word).

Some popular dictionaries that are used for converting arbitrary numbers to a pronounceable series of words include:

share|improve this answer
add comment

You can either make it just randomly generated numbers, or have a regex to cancel out the ones that are offensive:

/ass/ =~ userid
/boobs/ =~ userid
/morenaughtywordshere/ =~ userid
share|improve this answer
1  
Funny, cause I'd never think of either of those as offensive. –  DeadMG Apr 8 '12 at 20:28
    
I know…It's just a touchy subject to post real curse words on a SE site: meta.stackexchange.com/questions/22232/… –  Billjk Apr 8 '12 at 20:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.