30
\$\begingroup\$

Inspired by a recent Daily WTF article...

Write a program or function that takes a GUID (string in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, where each X represents a hexadecimal digit), and outputs the GUID incremented by one.

Examples

>>> increment_guid('7f128bd4-b0ba-4597-8f35-3a2f2756dfbb')
'7f128bd4-b0ba-4597-8f35-3a2f2756dfbc'
>>> increment_guid('06b86883-f3e7-4f9d-87c5-a047e89a19fa')
'06b86883-f3e7-4f9d-87c5-a047e89a19fb'
>>> increment_guid('89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2cf')
'89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2d0'
>>> increment_guid('89f25f2f-2f7b-4aa6-b9d7-46a98e3cb29f')
'89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2a0'
>>> increment_guid('8e0f9835-4086-406b-b7a4-532da46963ff')
'8e0f9835-4086-406b-b7a4-532da4696400'
>>> increment_guid('7f128bd4-b0ba-4597-ffff-ffffffffffff')
'7f128bd4-b0ba-4598-0000-000000000000'

Notes

  • Unlike in the linked article, incrementing a GUID that ends in F must “carry” to the previous hex digit. See examples above.
  • You may assume that the input will not be ffffffff-ffff-ffff-ffff-ffffffffffff.
  • For hex digits above 9, you may use either upper (A-F) or lower (a-f) case.
  • Yes, GUIDs may start with a 0.
  • Your output must consist of exactly 32 hex digits and 4 hyphens in the expected format, including any necessary leading 0s.
  • You do not have to preserve the version number or other fixed bits of the GUID. Assume it's just a 128-bit integer where none of the bits have any special meaning. Similarly, GUIDs are assumed to sort in straightforward lexicographical order rather than in the binary order of a Windows GUID struct.
  • If writing a function, the input may be of any sequence-of-char data type: string, char[], List<char>, etc.
\$\endgroup\$
  • 1
    \$\begingroup\$ Are we supposed to leave the 6 fixed bits in the UUIDv4 intact? \$\endgroup\$ – Filip Haglund Jan 17 at 10:32
  • 2
    \$\begingroup\$ @FilipHaglund: No, just treat the GUID as a 128-bit number, where none of the bits have any special meaning. Similarly, GUIDs are assumed to sort in straightforward lexicographical order rather than in the binary order of a Windows GUID struct. \$\endgroup\$ – dan04 Jan 17 at 14:24
  • 3
    \$\begingroup\$ Suggested test case: 89f25f2f-2f7b-4aa6-b9d7-46a98e3cb29f to ensure that answers can make the transition 9 -> a. \$\endgroup\$ – Kamil Drakari Jan 17 at 14:35
  • 1
    \$\begingroup\$ @dana: You may use any data type for which your language's equivalent of C#'s foreach (char ch in theInput) is valid. \$\endgroup\$ – dan04 Jan 17 at 14:39

23 Answers 23

7
\$\begingroup\$

05AB1E, 17 15 18 bytes

Saved 2 bytes thanks to Kevin Cruijssen

'-K1ìH>h¦Ž¦˜S·£'-ý

Try it online! or as a Test Suite

Explanation

'-K                  # remove "-" from input
   1ì                # prepend a 1 (to preserve leading 0s)
     H               # convert from hex to base 10
      >              # increment
       h             # convert to hex from base 10
        ¦            # remove the extra 1
         Ž¦˜S·       # push [8, 4, 4, 4, 12]
              £      # split into parts of these sizes
               '-ý   # join on "-"
\$\endgroup\$
  • \$\begingroup\$ Dang, you beat me to it.. Had something very similar, but with žKà instead of '-K. Btw, you can save 2 bytes by changing •É]•S3+ to Ž¦˜S·. \$\endgroup\$ – Kevin Cruijssen Jan 17 at 10:22
  • \$\begingroup\$ @KevinCruijssen: Thanks! I don't know how many times I've kept forgetting that Ž is a thing now... \$\endgroup\$ – Emigna Jan 17 at 10:25
  • \$\begingroup\$ I un-accepted this answer because someone pointed out that it will drop leading 0's. Please fix. \$\endgroup\$ – dan04 Jan 18 at 2:36
  • \$\begingroup\$ @dan04: Good call! I hadn't thought of that. Should be fixed now :) \$\endgroup\$ – Emigna Jan 18 at 6:54
20
\$\begingroup\$

Python 2, 50

  • 3 bytes saved thanks to @Dennis.
lambda s:UUID(int=UUID(s).int+1)
from uuid import*

Try it online!

\$\endgroup\$
11
\$\begingroup\$

JavaScript (ES6), 85 bytes

The output string is in lowercase.

s=>(g=(c,x=+('0x'+s[--n])+!!c)=>1/x?g(x>>4)+(x&15).toString(16):~n?g(c)+'-':'')(n=36)

Try it online!

Commented

s => (                   // s = GUID
  g = (                  // g = recursive function taking:
    c,                   //   c = carry from the previous iteration
    x = +('0x' + s[--n]) //   x = decimal conversion of the current digit
        + !!c            //       add the carry
  ) =>                   //
    1 / x ?              // if x is numeric:
      g(x >> 4) +        //   do a recursive call, using the new carry
      (x & 15)           //   and append the next digit
      .toString(16)      //   converted back to hexadecimal 
    :                    // else:
      ~n ?               //   if n is not equal to -1:
        g(c)             //     do a recursive call, leaving the current carry unchanged
        + '-'            //     and append a hyphen
      :                  //   else:
        ''               //     stop recursion
)(n = 36)                // initial call to g with n = 36 and a truthy carry
\$\endgroup\$
5
\$\begingroup\$

Python 2, 82 bytes

q='f0123456789abcdef--'
f=lambda s:[str,f][s[-1]in'f-'](s[:-1])+q[q.find(s[-1])+1]

Try it online!

No imports or hex conversion.

This scans from the back of the string, moving each character along the cycle 0123456789abcdef, with - going to itself. After it hits a symbol other than f or -, it stops scanning leftwards, and just returns the remainder unchanged. This solution isn't specific to the UUID format -- any number of blocks of any number of hex letters would work.

The base case of [str,f][s[-1]in'f-'](s[:-1]) is a trick I haven't seen used in a golf before. It terminates the recursion without any if, and, or, or other explicit control flow.

Based on the condition [s[-1]in'f-'] of the last character, the code either returns f(s[:-1]) or just s[:-1] unchanged. Since str is the identity on strings, we can select one of the functions [str,f] and apply it to s[:-1]. Note that the recursive call with f is not made if it is not chosen, getting around the common issue problem that Python eagerly evaluates unused options, leading to infinite regress in recursions.

\$\endgroup\$
  • \$\begingroup\$ well, there goes my brain for the morning. \$\endgroup\$ – don bright Jan 22 at 19:03
3
\$\begingroup\$

APL (Dyalog Unicode), 46 bytesSBCS

Anonymous tacit prefix function.

⎕CY'dfns'
(∊1hex 16(|+1⌽=)⍣≡1+@32dec¨)@('-'≠⊢)

Try it online!

⎕CY'dfns'copy the "dfns" library (to get hex and dec)

()
 the argument
 differs from
'-' a dash
()@ on the subset consisting of the locations at which the above criterion is true, apply:
dec¨ convert each hexadecimal character to a decimal number
 …@32at position 32 (the last digit), apply:
  1+ increment
16()⍣≡ repeatedly apply with left argument 16 until stable:
  = compare (gives mask where the hexadecimal digits are 16)
  1⌽ cyclically rotate one step left (this is the carry bit)
  |+ to that, add the division remainder when divided (by sixteen, thus making all 16 into 0)
1hex  turn digits into length-one hexadecimal character representations
ϵnlist (flatten)

\$\endgroup\$
3
\$\begingroup\$

Java 11, 152 149 111 108 bytes

s->{var b=s.getLeastSignificantBits()+1;return new java.util.UUID(s.getMostSignificantBits()+(b==0?1:0),b);}

-38 bytes thank to @OlivierGrégoire.
-3 bytes thanks to @ASCII-only.

Try it online.

Explanation:

s->{         // Method with UUID as both parameter and return-type
  var b=s.getLeastSignificantBits()
             //  Get the 64 least significant bits of the input-UUID's 128 bits as long
        +1;  //  And increase it by 1
  return new java.util.UUID(
             //  Return a new UUID with:
    s.getMostSignificantBits()
             //   The 64 most significant bits of the input-UUID's 128 bits as long
    +(b==0?  //    And if the 64 least significant bits + 1 are exactly 0:
       1     //     Increase the 64 most significant bits by 1 as well
      :      //    Else:
       0,    //     Don't change the 64 most significant bits by adding 0
     b);}    //   And the 64 least significant bits + 1

Old 149 bytes answer:

s->{var t=new java.math.BigInteger(s.replace("-",""),16);return(t.add(t.ONE).toString(16)).replaceAll("(.{4})".repeat(5)+"(.*)","$1$2-$3-$4-$5-$6");}

Try it online.

Explanation:

s->{                              // Method with String as both parameter and return-type
  var t=new java.math.BigInteger( //  Create a BigInteger
         s.replace("-",""),       //  Of the input-string with all "-" removed
         16);                     //  Converted from Hexadecimal
  return(t.add(t.ONE)             //  Add 1
         .toString(16))           //  And convert it back to a Hexadecimal String
         .replaceAll("(.{4})".repeat(5)+"(.*)",
                                  //  And split the string into parts of sizes 4,4,4,4,4,rest
           "$1$2-$3-$4-$5-$6");}  //  And insert "-" after parts of size 8,4,4,4,
                                  //  and return it as result
\$\endgroup\$
  • 1
    \$\begingroup\$ 111 bytes \$\endgroup\$ – Olivier Grégoire Jan 17 at 16:04
  • \$\begingroup\$ @OlivierGrégoire Hadn't thought about using an actual UUID! Nice and shorter alternative. :D \$\endgroup\$ – Kevin Cruijssen Jan 17 at 18:10
  • 1
    \$\begingroup\$ 109 \$\endgroup\$ – ASCII-only Jan 18 at 2:13
  • \$\begingroup\$ -1 more with var instead of long \$\endgroup\$ – ASCII-only Jan 18 at 2:15
3
\$\begingroup\$

Ruby -pl, 62 57 55 bytes

$_="%032x"%-~gsub(?-,"").hex
7.step(22,5){|i|$_[i]+=?-}

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Python 3, 50 bytes

from uuid import*
lambda u:UUID(int=UUID(u).int+1)

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 2, 113 112 bytes

def f(s):a=hex(int(s.replace('-',''),16)+1+2**128);return'-'.join((a[3:11],a[11:15],a[15:19],a[19:23],a[23:-1]))

Try it online!

Without imports

\$\endgroup\$
2
\$\begingroup\$

Retina 0.8.2, 21 bytes

T`FfdlL`0dlL`.[-Ff]*$

Try it online! Link includes test cases. 9 becomes a. Explanation: The regex matches all trailing fs and -s plus one preceding character. The transliteration then cyclically increments those characters as if they were hex digits. Alternate approach, also 21 bytes:

T`L`l
T`fo`dl`.[-f]*$

Try it online! Link includes test cases. Works by lowercasing the input to simplify the transliteration. Would therefore be 15 bytes if it only had to support lowercase. Try it online! Link includes test cases.

\$\endgroup\$
2
\$\begingroup\$

MATLAB, 138 bytes

a=1;Z=a;for r=flip(split(input(''),'-'))'
q=r{:};z=dec2hex(hex2dec(q)+a,nnz(q));try
z+q;a=0;catch
z=~q+48;end
Z=[z 45 Z];end;disp(Z(1:36))

Fixed a bug in case a chunk is all zeros. Also golfed off a lot by abusing try/catch. Net result: 0 bytes saved.

An attempt to 'cheat' by using java.util.UUID failed because the long value returned from java.util.UUID.get[Most/Least]SignificantBits gets converted to a double which incurs a loss of precision. I invite you to take a look at this table and silently utter "...but why?"

Explanation

The hex2dec function spits out a double, so it cannot process the entire GUID at once to avoid exceeding flintmax. Instead, we have to process the GUID chunk by chunck, using split. The variable a checks if we need to carry a one, and cheatingly also is the initial increment we add. The condition for carrying over is whether the lengths of the original and incremented strings are no longer equal.

Original version was just under 160 bytes so I'd like to think this should not be easy to outgolf.

\$\endgroup\$
2
\$\begingroup\$

Python 2, 99 bytes

s='%032x'%-~int(input().replace('-',''),16)
print'-'.join((s[:8],s[8:12],s[12:16],s[16:20],s[20:]))

Try it online!

No uuid.UUID usage.

\$\endgroup\$
2
\$\begingroup\$

C# (Visual C# Interactive Compiler), 77 bytes

x=>{for(int i=35,c;(x[i]=(char)((c=x[i--])<48?c:c==57?65:c>69?48:c+1))<49;);}

Try it online!

-1 byte thanks to @ASCIIOnly!

Anonymous function that takes a char[] as input and outputs by modifying an argument.

Input is scanned from right to left and replaced using the following rules.

  • The - character is ignored and processing continues
  • The F character is converted to 0 and processing continues
  • The 9 character is converted to A and processing stops
  • The characters A-E and 0-8 are incremented by 1 and processing stops
\$\endgroup\$
  • 2
    \$\begingroup\$ ==70 -> >69 \$\endgroup\$ – ASCII-only Jan 18 at 1:52
  • \$\begingroup\$ Excellent - Thanks :) \$\endgroup\$ – dana Jan 18 at 4:29
2
\$\begingroup\$

Powershell, 101 bytes

for($p=1;$d=+"$args"[--$i]){$d+=$p*(1-@{45=1;57=-7;70=23;102=55}.$d)
$p*=$d-in45,48
$r=[char]$d+$r}$r

Try it online!

No external library or hex conversion. Any string length. Lower case and upper case are allowed. Input string matching to ^[f-]*$ is allowed too.

This script scans from the back of the string and inrement each char by the value from hashtable:

  • -: increment=1-1
  • 9: increment=1+7, result=A
  • F: increment=1-23, result=0
  • f: increment=1-55, result=0
  • increment=1 for other chars

Next, the script uses $p to determine whether to increment the current char.

Test script:

$f = {

for($p=1;$d=+"$args"[--$i]){$d+=$p*(1-@{45=1;57=-7;70=23;102=55}.$d)
$p*=$d-in45,48
$r=[char]$d+$r}$r

}

@(
    ,('f','0')
    ,('F','0')
    ,('0','1')
    ,('9','A')
    ,('A','B')
    ,('a','b')
    ,('0-f','1-0')
    ,('0-F','1-0')
    ,("7f128bd4-b0ba-4597-8f35-3a2f2756dfbb","7f128bd4-b0ba-4597-8f35-3a2f2756dfbc")
    ,("06b86883-f3e7-4f9d-87c5-a047e89a19f9","06b86883-f3e7-4f9d-87c5-a047e89a19fa")
    ,("89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2cf","89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2d0")
    ,("8e0f9835-4086-406b-b7a4-532da46963ff","8e0f9835-4086-406b-b7a4-532da4696400")
    ,("7f128bd4-b0ba-4597-ffff-ffffffffffff","7f128bd4-b0ba-4598-0000-000000000000")
    ,("89f25f2f-2f7b-4aa6-b9d7-46a98e3cb29f","89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2a0")
    ,("ffffffff-ffff-ffff-ffff-ffffffffffff","00000000-0000-0000-0000-000000000000")
) | % {
    $guid,$expected = $_
    $result = &$f $guid
    "$($result-eq$expected): $result"
}

Output:

True: 0
True: 0
True: 1
True: A
True: B
True: b
True: 1-0
True: 1-0
True: 7f128bd4-b0ba-4597-8f35-3a2f2756dfbc
True: 06b86883-f3e7-4f9d-87c5-a047e89a19fA
True: 89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2d0
True: 8e0f9835-4086-406b-b7a4-532da4696400
True: 7f128bd4-b0ba-4598-0000-000000000000
True: 89f25f2f-2f7b-4aa6-b9d7-46a98e3cb2A0
True: 00000000-0000-0000-0000-000000000000
\$\endgroup\$
1
\$\begingroup\$

Perl 6, 65 bytes

{(:16(TR/-//)+1).base(16).comb.rotor(8,4,4,4,*)».join.join('-')}

Test it

\$\endgroup\$
  • 1
    \$\begingroup\$ The OP has clarified that leading zeroes must be preserved. \$\endgroup\$ – Dennis Jan 18 at 3:00
  • \$\begingroup\$ 56 bytes with leading zeroes \$\endgroup\$ – Jo King Jan 18 at 7:32
  • 1
    \$\begingroup\$ Or 53 bytes by handling stuff more manually \$\endgroup\$ – Jo King Jan 18 at 8:57
1
\$\begingroup\$

JavaScript (Node.js), 81 bytes

s=>s.replace(/.([f-]*)$/,(s,y)=>(('0x'+s[0]|0)+1).toString(16)+y.replace(/f/g,0))

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Jelly, 20 bytes

-2 (and a bug fix) thanks to Dennis!

ØhiⱮṣ0µẎḅ⁴‘ḃ⁴ịØhṁj”-

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 126 bytes

$a=("{0:X32}" -f (1+[Numerics.BigInteger]::Parse($args[0]-replace"-", 'AllowHexSpecifier')));5..2|%{$a=$a.Insert(4*$_,"-")};$a

Try it online!

Pretty trivial answer. Just thought I'd get the beloved PowerShell added to the list :)

\$\endgroup\$
0
\$\begingroup\$

Perl 5, 64 bytes

$c=reverse((1+hex s/-//gr)->as_hex);$c=~s/..$//;s/[^-]/chop$c/ge

The number of parentheses necessary here makes me sad, but -> binds very tightly, as ->as_hex is the quickest way I can find to get hexadecimal-formatted output.

Run with perl -Mbigint -p. Basically, it just converts the number to a bigint hexadecimal, adds one, and then subtitutes the digits of the result back into the original value, leaving dashes untouched.

\$\endgroup\$
0
\$\begingroup\$

Rust, 258 bytes

let x=|s:&str|s.chars().rev().scan(1,|a,c|{let d=c.to_digit(16).unwrap_or(99);match(d,*a){(15,1)=>{*a=1;Some(0)}(0..=14,1)=>{*a = 0;Some(d + 1)}_=> Some(d),}}).collect::<Vec<u32>>().iter().rev().for_each(|d| print!("{}", std::char::from_digit(*d, 16).unwrap_or('-')));

yes its long.. but technically its only one line with 1 expression? and no fancy libraries? and it will not crash on a fuzz input? ungolf:

let x=|s:&str|s.chars().rev().scan(1, |a, c| {
            let d = c.to_digit(16).unwrap_or(99);
            match (d, *a) {
                (15, 1) => {*a = 1;Some(0)}
                (0..=14, 1) => {*a = 0;Some(d + 1)}
                _ => Some(d),
            }
        }).collect::<Vec<u32>>().iter().rev()
        .for_each(|d| print!("{}", std::char::from_digit(*d, 16).unwrap_or('-')));

try it on rust playground

\$\endgroup\$
0
\$\begingroup\$

16/32/64-bit x86 assembly code, 28 bytes

bytes: 83C623FDAC3C2D74FB403C3A7502B0613C677502B03088460173E9C3

code:

     add esi, 35       ;point to end of string - 1
     std               ;go backwards
l1:  lodsb             ;fetch a character
     cmp al, '-'
     je  l1            ;skip '-'
     inc eax           ;otherwise increment
     cmp al, '9' + 1
     jne l2            ;branch if not out of numbers
     mov al, 'a'       ;otherwise switch '9'+1 to 'a'
l2:  cmp al, 'f' + 1   ;sets carry if less
     jne l3            ;branch if not out of letters
     mov al, '0'       ;otherwise switch 'f'+1 to '0'
                       ;and carry is clear
l3:  mov [esi + 1], al ;replace character
     jnb l1            ;and loop while carry is clear
     ret

Call with ESI pointing to GUID. Replace ESI with SI for 16-bit, or RSI for 64-bit (and +2 bytes).

\$\endgroup\$
0
\$\begingroup\$

C (clang), 62 bytes

g(char*i){for(i+=36;(*--i-45?*i+=*i-70?*i-57?1:8:-22:0)<49;);}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ wait. does the lowercase/uppercase check not cost anything??? \$\endgroup\$ – ASCII-only Jan 22 at 7:58
  • \$\begingroup\$ i mean, it can handle both lowercase and uppercase at no cost to bytecount?! \$\endgroup\$ – ASCII-only Jan 22 at 9:16
  • \$\begingroup\$ Ah ok.. ch-70%32 ? : to '0'... 64 and 96 are multiple of 32 so 70-6 and 102-6 %32 . \$\endgroup\$ – AZTECCO Jan 22 at 10:15
  • 1
    \$\begingroup\$ you don't actually have to handle both, so 64 \$\endgroup\$ – ASCII-only Jan 23 at 4:53
0
\$\begingroup\$

Common Lisp, 166 bytes

(lambda(s &aux(r(format()"~32,'0x"(1+(parse-integer(remove #\- s):radix 16)))))(format()"~{~a~^-~}"(mapcar(lambda(x y)(subseq r x y))#1='(0 8 12 16 20 32)(cdr #1#))))

Try it online!

\$\endgroup\$

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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