1

I'm in a situation where I need to run some javascript in a place where I cannot use external packages.

Ideally the function should take a string as parameter and return a string in the format of a uuid (not random), based on the string parameter of course.

I've been searching all over the internet but except a few npm packages I could not find a simple and short function for doing so, since most of the functions are just random uuidv4 functions.

Since I need this to run some js in an external application, it is important that no external dependencies are used, and also the shorter the better.

Use case:

I have an entity without an id (uuid) field. It does have 2 other ids however. Before I persist it I want to generate an id in the format of a uuid based on a concatenated string of ${fooId}-${barId} so I will be able to get the resource by this id from the API.

If I did not have the limitation of not being able to use external dependencies / npm packages and scripts, I would have used the uuid package and the uuidv5. Sadly I do not have this possibility, so I thought it would be possible to to this in a single vanilla js function.

If I was not clear before I need to figure out what to put here

const stringToUuid = (str) => {
  // return string formatted as a uuid, based on the str parameter
}
E_net4
  • 27,810
  • 13
  • 101
  • 139
Dac0d3r
  • 2,176
  • 6
  • 40
  • 76
  • 1
    Search for *creating a hash from a string*. – Titus Mar 23 '20 at 21:05
  • Does this answer your question? [Create GUID / UUID in JavaScript?](https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript) – DCR Mar 23 '20 at 21:12
  • You shouldn't be generating UUIDs based on strings - that's a pretty sure way to make them something that's definitely not Universally Unique Identifiers. – AKX Mar 23 '20 at 21:13
  • @DCR no, why would you think that? – Dac0d3r Mar 23 '20 at 21:14
  • @titus I guess I'd need to generate a md5 / sha1 hash or something, and then use add the dashes afterwards. Seems like a lot of work in vanilla js, since I cannot use any dependencies. Had hoped it would be possible to do with less code. – Dac0d3r Mar 23 '20 at 21:16
  • @AKX I need this since I do not have a uuid as my id field, but will need to generate it from 2 other fields on that entity before I persist it. So the uniqueness would be the combination of those 2 values in a concatenated string. But I'd like it represented as a uuid similar to the uuidv5 from the uuid npm package which I could have used if I had the possibility of importing an external dependency, which I don't – Dac0d3r Mar 23 '20 at 21:19
  • You can write your own hashing method or find a simple one online. Hashing is just a consistent way of reducing something's size, the main requirement is to get the same result for the same thing, how you do that is up to you. – Titus Mar 23 '20 at 21:26
  • Then I'm left with turning that simple hash into the format of a uuid. I don't really feel like this is helping. – Dac0d3r Mar 23 '20 at 21:34
  • That is the easy part, it can be as simple as `"1234567890".match(/.{2}/g).join("-")` – Titus Mar 23 '20 at 21:38
  • Hmm not sure what to say. The hint's your giving me is not helping me that much. I have once found a function somewhere on the internet that took a string and did output a nice uuid-formatted string based on the str parameter. It was less than 10 lines of code and did not have any external dependencies. I couldn't find it again, which is why I created this question in hopes that someone would know how to make such a short function. Now that I look into 32bit hashing and then some regex magic after, this task seems overly complicated. – Dac0d3r Mar 23 '20 at 21:52
  • Is the combination of `fooId` and `barId` unique? If that's the case you could roll over it replacing the characters of a uuid mask. That should be unique too, right? – vicpermir Mar 23 '20 at 21:56
  • @vicpermir yes `${fooId}-${barId}` would be a unique combination. But I need them as a single string in the form of a uuid. I don't understand what you mean by "roll over it replacing the characters of a uuid mask" – Dac0d3r Mar 23 '20 at 22:18
  • 1
    I have answered with what I meant but it's a pretty dumb solution so... maybe wait for other answers :) – vicpermir Mar 23 '20 at 22:36

1 Answers1

5

If the combination of fooId and barId is unique you could iterate over them and fill some UUID mask.

const stringToUuid = (str) => {
  str = str.replace('-', '');
  return 'xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function(c, p) {
    return str[p % str.length];
  });
}

var input  = "813538-359512";
var output = stringToUuid(input);

console.log('Input: ' + input);
console.log('Output: ' + output);

The output should be a valid UUID string.

Caveats about fooId and barId:

  • Both must contain only hexadecimal characters (I'm guessing they are numbers?)
  • The length of both combined must be below 32 characters, otherwise the combination is longer than the characters replaced in the UUID mask and you could run into duplicates

It's a really simplistic way to solve your problem to be honest, I'm not sure of the implications or how robust it is.

If you want to combine two UUID to generate a third one you could operate on each character in pairs. In this case, it seems the most used operation is a bitwise XOR so that's what I'll do in this example:

const stringToUuid = (uuid1, uuid2) => {
  return 'xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function(c, p) {
    var c1 = uuid1.charAt(p);
    var c2 = uuid2.charAt(p);
    return (parseInt(c1, 16) ^ parseInt(c2, 16)).toString(16).charAt(0);
  });
}

// Both must be valid UUID
var uuid1 = 'e7d24026-3081-4789-a6bd-34d8b69365ac';
var uuid2 = '6556c838-df63-461a-a415-852aa464f344';
var output = stringToUuid(uuid1, uuid2);

console.log('Uuid1: ' + uuid1);
console.log('Uuid2: ' + uuid2);
console.log('Output: ' + output);

The result should still be a valid UUID, but I guess you lose on uniqueness.

vicpermir
  • 3,544
  • 3
  • 22
  • 34
  • Thanks for your answer. Ideally I hope for a solution that would work with any string as a parameter. In this case both fooId and bazId are actually uuids, so this will not quite work, unless of course I remove the dashes from them, which I could of course just do. I'll leave this question open a few days to see if I get more answers. – Dac0d3r Mar 23 '20 at 23:13
  • I think in line 2 it should be changed to `str = str.replace(/-/g, '');` - at least to work for uuids in the input variable – Dac0d3r Mar 23 '20 at 23:20
  • I have updated my answer, I didn't understand that you wanted to merge two `UUID` into a third one (just two numerical `IDs`). Quite a weird requirement honestly, phew :P – vicpermir Mar 24 '20 at 06:57
  • Thanks. I don't understand why people say it's such a weird requirement, since I just need a unique id in a field before I persist it, since I want to be able to get the resource by that id instead of having to specify 2 ids, fooId and barId. Why is that such a weird requirement? Generating a string with the format of a uuid from a random string is not THAT unheard of is it? :D – Dac0d3r Mar 24 '20 at 11:54
  • 1
    Weird in the sense that usually you generate a random UUID and never operate on it. But you are right, that's what you need and it should be doable :P – vicpermir Mar 24 '20 at 12:12
  • how would you decode this back to strings? – ScipioAfricanus Jul 12 '22 at 19:01