Sandbox

French license plates come in a sequential order, following a specific pattern of numbers and letters : AB-012-CD

## Challenge

Write a program or function that, for a given number, outputs the corresponding french license plate number. Your program should not handle any special case as specified in the linked page. It should be able to generate the full 26*26*1000*26*26 => 456 976 000 possible plates, or as far as your language can support.

The numbering system goes as follows:

• AA-000-AA to AA-999-AA (numbers evolve first);
• AA-000-AB to AA-999-AZ (then the last letter on the right);
• AA-000-BA to AA-999-ZZ (then the first letter on the right);
• AB-000-AA to AZ-999-ZZ (then the last letter on the left);
• BA-000-AA to ZZ-999-ZZ (then the first letter on the left).

### Input

• The plate number's index as an integer

### Output

• The corresponding french license plate number

• Letters have to be uppercase
• You can use both 0-based and 1-based indexing to generate the plates (meaning AA-000-AA can correspond to 0or 1, assuming all the other test cases use the same indexing.

This is code-golf, shortest answer in every language wins!

## Test cases (0-based indexing)

          0 -> AA-000-AA
1 -> AA-001-AA
999 -> AA-999-AA
1000 -> AA-000-AB
675 999 -> AA-999-ZZ
676 000 -> AB-000-AA
456 975 999 -> ZZ-999-ZZ

• Here are some more requirements, directly from Wikipedia, if you want to create a harder variation : "This figure excludes three letters that are not used: I, O and U, as they can be confused with 1, 0 and V, respectively. It also excludes the SS combination because it is reminiscent of the Nazi organisation and WW in the first group of letters as it indicates a temporary plate." Sep 25, 2019 at 6:50
• @EricDuminil I purposefully excluded it because it just added unfun constraints on the challenge. But it's true it could be interesting to do, but even with "bonus points", I doubt it would be worth implementing these rules Sep 25, 2019 at 7:33

# Pure Bash (no external utils), 64

• 2 bytes saved thanks to @NahuelFouilleul
x={A..Z}
eval f=($x$x-%03d-$x$x)
printf ${f[$1/1000]} $[$1%1000]


Try it online! - takes about 10s to run over the 7 testcases.

• Line #1 is a simple assignment of a string to a variable
• Line #2 is a brace expansion to build an array of printf format strings, one for all 456,976 possible letter combinations, with the digits not yet specified. The eval is required to ensure variable expansion (of x) occurs before brace expansion.
• Line #3 indexes the array to get the appropriate format string and takes the digits portion as its parameter.
• -2bytes Sep 24, 2019 at 15:23

# Perl 5 (-ap), 47 bytes

$_=AAAA000;$_++while$F--;s/(..)(\d+)/-$2-$1/  Try it online! # PHP, 74 bytes for($a=AAAA000;$argn--;$a++);echo preg_replace('/(..)(\d+)/','-$2-$1',$a);  Try it online! • +1 for PHP, I knew we could increment letters in PHP, but I didn't know that we can increment a combination of letters and digits. PHP amazes me every day! And thanks I learned something new. Sep 24, 2019 at 12:39 # Python 3, 79 78 77 bytes lambda n:f"%c%c-{n%1000:03}-%c%c"%(*(65+n//1000//26**i%26for i in[3,2,1,0]),)  Try it online! I somehow never realised that the f"string" format shortcut exists until seeing Black Owl Kai's answer. • 78 bytes by replacing tuple by (*...,) Sep 23, 2019 at 22:27 • Using f"string" makes your answer Python 3.6+ exclusive, just so you are aware. Nice work though! Sep 26, 2019 at 19:31 ## Ruby, 6159 55 bytes ->n{s='AA-AA000-';eval's.succ!;'*n;s+=s[5,4];s[0,9]}  Also 55 bytes: ->n{s='AA-AA000-';eval's.succ!;'*n;s+=s.slice!5,4;s}  Try it online! This initializes a counter to AA-AA000-, increments it n times (by multiplying a string of the code that does so by n and evaling), and then moves the last 4 characters after the 3nd. • ->n{s=('AA-AA000-'..?Z*9).step.take(n)[-1];s+=s.slice!5,4;s} is longer but I wonder if it's possible to shorten it. Sep 24, 2019 at 20:10 • In theory, ->n{s=[*'AA-AA000-'..?Z*9][n];s+=s.slice!5,4;s} should work and is only 50 bytes long, but it generates every possible plate first. :-/ Sep 25, 2019 at 6:58 • "s+=s.slice!3,2" for 50 bytes – G B Sep 25, 2019 at 8:47 • Then this should also work: 45 bytes – G B Sep 25, 2019 at 10:52 # PHP, 9684 79 bytes -5 byte thanks to Ismael Miguel's great comments. for($s=AAAA;$x++^$argn/1e3;)$s++;printf('%.2s-%03u-'.$s.$s,$s,$argn%1e3);  Try it online! I take advantage of the fact that you can increment letters in PHP! So AAAA++ would become AAAB and AAAZ++ would become AABA. I calculate how many times the letters have to be incremented by getting integer part of input/1000. Then increment the four characters length that many times and its first two and last two characters will automatically become the left and right side of the plate. For example for input of 675999 number of letter increments is (int)(675999 / 1000) = 675, so AAAA will become AAZZ. Finally, the middle number is calculated by input%1000 and everything is printed in the specified format with help of printf. %.2s prints first two characters of the string, %03u pads the number in the left with 3 zeros. • @Elcan Sorry, fixed the issues at a cost of 12 bytes. I have an excuse of being under attack by three cats, for my messing up :P Sep 23, 2019 at 19:53 • Instead of %0.2s you can write %.2s. That saves you 1 byte. (As a tiny tip: if you want to output a decimal number with a specific number of decimal places, you can do %.2f (or any other modifier) as it works the same way) Sep 24, 2019 at 9:40 • @IsmaelMiguel Thanks, didn't know we could drop the 0. Edit: looking at documentations, it seems I didn't even need it at the first place :P Sep 24, 2019 at 10:38 • Oh, yeah, you can drop those. Also, you can do $x++^$argn/1e3 instead of $x++<(0^$argn/1e3) and you should save 4 bytes. This will loop until ($x++^$argn/1e3) === 0, and it is 0 when $x and $argn/1e3 are the same integer number (using ^ will cast the numbers to integer). You can try this on sandbox.onlinephpfunctions.com/code/… Sep 24, 2019 at 11:16 • @IsmaelMiguel Thanks again, very clever idea. You made this answer shorter than JS one and that is an achievement :P Sep 24, 2019 at 11:28 # C, 88 86 bytes #define d(b)a/b/1000%26+65 f(a){printf("%c%c-%03d-%c%c",d(17576),d(676),a%1000,d(26),d(1));}  Pretty simple, it uses division and modulus to extract the fields, adds 'A' for the letters to map them to ASCII characters, and printf formatting for the numbers. Try it online! ## Haskell, 858179 77 bytes ([h++'-':n++'-':t|h<-q"AZ",t<-q"AZ",n<-q"099"]!!) q g=mapM(\_->[g!!0..g!!1])g  Try it online! # 05AB1E, 2522 20 bytes Au2ããs₄‰UèX₄+¦'-.øý  -2 bytes (and increased the performance by not generating the entire list) thanks to @Grimy. 0-based indexing. Explanation: Au # Push the lowercase alphabet, and uppercase it 2ã # Create all possible pairs by taking the cartesian product with itself: # ["AA","AB","AC",...,"ZY","ZZ"] ã # Get the cartesian product of this list with itself: # [["AA","AA"],["AA","AB"],...,["ZZ","ZZ"]] s # Swap to push the (implicit) input ₄‰ # Take the divmod-1000 of it # i.e. 7483045 becomes [7483,45]  # Push these values separated to the stack U # Pop and store the remainder part in variable X è # Index the integer part into the list of letter-pairs we created earlier # i.e. 7483 will result in ["AL","BV"] X # Push the remainder part from variable X again ₄+ # Add 1000 to it ¦ # And remove the leading 1 (so now the number is padded with leading 0s) # i.e. 45 becomes 1045 and then "045" '-.ø '# Surround this with "-" (i.e. "045" becomes "-045-") ý # Join the two pairs of letters by this # i.e. ["AL","BV"] and "-045-" becomes "AL-045-BV" # (after which the top of the stack is output implicitly as result)  The last part (s₄‰UèX₄+¦'-.øý) could be I₄÷èI₄+3.£.ý'-ý for an equal-bytes alternative: Try it online or verify all test cases. I₄÷ # Push the input, integer-divided by 1000 è # Use it to index into the letter-pairs we created earlier # i.e. 7483045 becomes 7483 and then ["AL","BV"] I₄+ # Push the input again, and add 1000 3.£ # Only leave the last three digits # i.e. 7483045 becomes 7484045 and then "045" .ý # Intersperse the pair with this # i.e. ["AL","BV"] and "045" becomes ["AL","045","BV"] '-ý '# And join this list by "-" # i.e. ["AL","045","BV"] becomes "AL-045-BV" # (after which the top of the stack is output implicitly as result)  • 20 with Au2ããI₄‰UèX₄+¦'-.øý or Au2ããI₄÷èI₄+3.£'-.øý. Sep 24, 2019 at 12:05 • @Grimy Thanks! And now it's also a lot faster by not generating and indexing into the complete list. :) Sep 24, 2019 at 12:52 # J, 5649 46 bytes 226950 A.'--',7$_3|.4,@u:65 48+/(4 3#26 10)#:]


Try it online!

-3 bytes thanks to FrownyFrog

The whole thing is nothing but 7 nested trains -- if that ain't fun, what is?

  ┌─ 226950
├─ A.
│        ┌─ '--'
──┤        ├─ ,
│        │      ┌─ 7
└────────┤      ├─ $│ │ ┌─ _3 └──────┤ ├─ |. │ │ ┌─ 4 └───┤ │ ┌─ , │ ├─ @ ─┴─ u: └────┤ │ ┌─ 65 48 │ ├─ / ───── + └─────┤ │ ┌─ '4 3#26 10' └───────┼─ #: └─ ]  • Cool! Using permutation is a nice way to format the resulting string. Sep 24, 2019 at 6:24 • 46 Sep 24, 2019 at 9:28 • Thanks @FrownyFrog! Sep 24, 2019 at 13:42 # JavaScript (Node.js), 82 bytes n=>'32-654-10'.replace(/\d/g,x=>Buffer([x&4?n/10**(x-4)%10+48:n/1e3/26**x%26+65]))  Try it online! # Ruby, 51 bytes ->n{[*?A*4..?Z*4][n/1e3][/../]+"-%03d-"%(n%1e3)+$'}


Try it online!

• Impressive. Congrats! Sep 24, 2019 at 20:06

# R, 101 bytes

b=0:3;a=scan()%/%c(10^b,1e3*26^b)%%rep(c(10,26),e=4);intToUtf8(c(a[8:7],-20,a[3:1]-17,-20,a[6:5])+65)


Try it online!

Just does the needed arithmetic computations. I saved 5 bytes by including in the vector a a useless value at a, allowing me to reuse the helper vector b.

Consider for example the second character (the B in AB-012-CD). That character changes every $$\26\times26\times1000=676\,000\$$ plates, so the value of that character for input n is the n %/% 676000 %% 26th letter of the alphabet, where %/% is integer division and %% is modulus in R. The other characters are computed similarly.

# Jelly,  26  22 bytes

ØAṗ2,ØDṗ3¤ṭŒp⁸ị2œ?j”-


A monadic Link accepting an integer (1-indexed) which yields a list of characters... Crazy-slow since it builds all the plates first!

Try it online! (wont complete)
Or try a reduced alphabet version (only "ABC" for the letters).

For code which completes in a timely manner here's a 32 byte full-program (0-indexed) which creates the single plate instead using modular arithmetic and numeric base decompression:

dȷ+“©L§“£ż’µḢṃØAṙ1¤ḊŒHW€jDḊ€$j”-  • Misses the dashes it seems, so for now it doesn't fit the challenge's rules :P Sep 23, 2019 at 20:56 • Ah, I completely ignored them as some kind of separator! Makes quite a difference for these methods :( Sep 23, 2019 at 21:00 • Sorry about that :c Still pretty nice to see it done in Jelly, even without ! Sep 23, 2019 at 21:07 • Added 7 byes to add them in, pretty sure there is a shorter overall method now... Sep 23, 2019 at 21:08 • Oops, thanks @Grimy - may as well golf that by 3 while I'm here :p – Jonathan Allan 1 min ago Sep 23, 2019 at 21:36 # APL+WIN, 61 bytes Prompts for integer: m←⎕av[4↑66+n←((4⍴26),1E3)⊤⎕]⋄(2↑m),'-',(¯3↑'00',⍕4↓n),'-',2↓m  Try it online! Courtesy of Dyalog Classic # Charcoal, 33 bytes Ｎθ¹✂Ｉ⁺θφ±³≔⪪⍘⁺Ｘ²⁶¦⁵÷θφα²η¹⊟ηＭ⁹←⊟η  Try it online! Link is to verbose version of code. Explanation: Ｎθ  Input the number. ¹  Print a -. ✂Ｉ⁺θφ±³  Add 1000 to the number, then cast the result to string, and print the last three digits. ≔⪪⍘⁺Ｘ²⁶¦⁵÷θφα²η  Divide the number by 1000, then add 26⁵, so the conversion to custom base using the uppercase alphabet results in a string of length 6, which is then split into pairs of letters. ¹  Print a -. ⊟η  Print the last pair of letters. Ｍ⁹←  Move to the beginning of the number plate. ⊟η  Print the rest of the desired letters. # Perl 6, 42 bytes {S/(..)(\d+)/-$1-$0/}o{('AAAA000'..*)[$_]}


Try it online!

Port of Grimy's Perl 5 solution. Slow for large input values.

# Excel, 183167155 147 bytes

-16 bytes thanks to @Neil. (6 by using E3)

-12 bytes thanks to @Keeta. (TRUNC instead of QUOTIENT)

-8 bytes thanks to @Jonathan Larouche (INT instead of TRUNC)

=CHAR(65+INT(A1/17576E3))&CHAR(65+MOD(INT(A1/676E3),26))&"-"&TEXT(MOD(A1,1E3),"000")&"-"&CHAR(65+MOD(INT(A1/26E3),26))&CHAR(65+MOD(INT(A1/1E3),26))


Concatenates 5 parts:

CHAR(65+INT(A1/17576E3))
CHAR(65+MOD(INT(A1/676E3),26))
TEXT(MOD(A1,1E3),"000")
CHAR(65+MOD(INT(A1/26E3),26))
CHAR(65+MOD(INT(A1/1E3),26))

• Does MOD(QUOTIENT(A1,1E3),26) not work? Also, why 1E3 for 1000 but not 26E3 etc?
– Neil
Sep 25, 2019 at 9:23
• Save even more by removing TRUNC altogether and moving the division to inside the MOD. =CHAR(65+A1/17576E3)&CHAR(65+MOD(A1/676E3,26))&"-"&TEXT(MOD(A1,1E3),"000")&"-"&CHAR(65+MOD(A1/26E3,26))&CHAR(65+MOD(A1/1E3,26)) bringing it down to 127 bytes. Sep 25, 2019 at 13:56
• I meant removing QUOTIENT. Originally I was suggesting to change quotient to trunc with a / instead of comma. Sep 25, 2019 at 14:10
• @Keeta, your 127 byte solution fails for some values: e.g. 456 975 996 --> [Z-996-ZZ Sep 26, 2019 at 9:09
• @Keeta, Seems like CHAR(65+) silently truncates decimals up to %.9999997614649. Bigger than that is rounded up. Compare CHAR(65+24.9999997614649) and CHAR(65+24.999999761465). Sep 26, 2019 at 9:58

# Clean, 107 bytes

import StdEnv
A=['A'..'Z']
N=['0'..'9']
$n=[[a,b,'-',x,y,z,'-',c,d]\\a<-A,b<-A,c<-A,d<-A,x<-N,y<-N,z<-N]!!n  Try it online! Defines $ :: Int -> [Char] giving the n-th zero-indexed licence plate.

# Japt, 21 bytes

Obscenely slow! Seriously, don't even try to run it!

Tip of the hat to Kevin for making me realise where I was going wrong when fighting to get this working last night.

;gBï ï ïq#d0o ùT3 û-5


Try it - limits the number range to 000-005.

;gBï ï ïq#d0o ùT3 û-5     :Implicit input of integer
g                        :Index into
; B                       :  Uppercase alphabet
ï                      :  Cartesian product with itself
ï                    :  Cartesian product of the result with itself
ï                  :  Cartesian product of that with
#d0              :    1000
o             :    Range [0,1000)
ùT3         :    Left pad each with 0 to length 3
û-5     :    Centre pad each with "-" to length 5
q                 :  Join the first element (the 2 pairs of letters) with the second (the padded digit string)


# Forth (gforth), 94 bytes

: x /mod 65 + emit ; : f dup 1000 / 17576 x 676 x ." -"swap 0 <# # # # #> type ." -"26 x 1 x ;


Try it online!

0-indexed. Input is taken from top of stack

### Code explanation

\ extract out some common logic
: x             \ start a new word definition
/mod          \ divide first argument by second and get both quotient and remainder
65 +          \ add 65 (ascii A) to quotient
emit          \ output
;               \ end word definition

: f             \ start a new word definition
dup 100 /     \ duplicate input and divide by 1000
17576 x       \ divide by 26^3 and output ascii char
676 x         \ divide by 26^2 and output ascii char
." -"         \ output "-"
swap 0        \ grab original number and convert to double-cell number
<# # # # #>   \ convert last 3 chars of number to a string
type ." -"    \ output string followed by "-"
26 x          \ divide result of last mod by 26 and output ascii char
1 x           \ output ascii char for remaining amount
;               \ end word definition



# q, 78 bytes

{sv["-","0"^-4$($:[x mod 1000]),"-"]2 2#(|).Q.A mod[x div 1000*26 xexp(!)4]26}


                                                    x div 1000*26 xexp(!)4     / input (floor) divided by 1000*26 ^ 0 1 2 3
mod[                      ]26  / mod 26
.Q.a                                / alphabet uppercase, indexed into by preceeding lines, for x=1000, we'd get "BAAA"
2 2#(|)                                    / reverse and cut into 2x2 matrix ("AA";"AB")
($:[x mod 1000]),"-" / string cast x mod 1000 and append "-" -4$                                                                / left pad to length 4, "  0-"
"-","0"^                                                                   / fill nulls (" ") with "0" and prepend "-"
sv[              x                ]y                                          / join elems of y by x


# T-SQL, 135 bytes

select concat(CHAR(65+(@i/17576000)),CHAR(65+(@i/676000)%26),'-',right(1e3+@i%1000,3),'-',CHAR(65+(@i/26000)%26),CHAR(65+(@i/1000)%26))


# Julia 1.0, 86 bytes

i->(join('A'.+digits(i÷1000,base=26,pad=4))string(i%1000,pad=3)*'-')[[4;3;8;5:8;2;1]]


Try it online!

# Python 2, 88 bytes

lambda n:g(n/676000)+'-%03d-'%(n%1000)+g(n/1000)
g=lambda n:chr(65+n/26%26)+chr(65+n%26)


Try it online!

• The save by mypetition under my answer can be applied for Python 2, too Sep 23, 2019 at 22:21

# Red, 130 127 bytes

func[n][g: func[a b c][t: copy""loop a[insert t b +(n % c)n: n / c]t]a: g 3 #"0"10
s: g 4 #"A"26 rejoin[s/1 s/2"-"a"-"s/3 s/4]]


Try it online!

# Python 3, 89 bytes

lambda n:h(n//676)+f"-{n%1000:03}-"+h(n)
h=lambda x:'%c%c'%(x//26000%26+65,x//1000%26+65)


Try it online!

-1 byte thanks to mypetlion

• Change chr(x//26000%26+65)+chr(x//1000%26+65) to '%c%c'%(x//26000%26+65,x//1000%26+65) to save 1 byte. Sep 23, 2019 at 20:40

# MATLAB, 113 bytes

c=@(x,p)char(mod(idivide(x,1000*26^p),26)+65);
s=@(n)[c(n,3),c(n,2),num2str(mod(n,1000),'-%03d-'),c(n,1),c(n,0)]


Explanations:

The first line define a function which will produce a char (from A to Z), function of 2 inputs. The index number x to convert into a plate number, and an integer p which will be used as an exponent for 26 (i.e. 26^p). This second input allow to adjust the calculations for the first alphanumeric plate digit (p=3) down to the last one (p=0).

For example, for the second digit, cycled every 1000*26*26 iterations, the operation: mod(idivide(x,1000*26^2),26) return an index between 0 and 25, which is then converted to an ASCII char by adding 65 (because the index are 0 based)

The second line simply concatenate characters together. Each alphanumeric character is calculated with the use of the function c(x,p), the numeric character are simply calculated with a modulo operation and converted to string.

Each component of the string composing the plate number is as follow:

digit #     |    how often is it cycled             |  code
----------------------------------------------------------------
digit 1     | cycle every 1000*26*26*26=1000*26^3   | c(n,3)
digit 2     | cycle every 1000*26*26   =1000*26^2   | c(n,2)
digit 3,4,5 | cycle every iteration                 | num2str(mod(n,1000),'-%03d-')
digit 6     | cycle every 1000*26      =1000*26^1   | c(n,1)
digit 7     | cycle every 1000         =1000*26^0   | c(n,0)


Since I can't let you try MATLAB online (edit: actually you can try it online ), I'll let MATLAB users the possibility to verify the test cases:

% chose some test cases
n = uint32([0;1;999;1000;675999;676000;456975999]) ;

% work out their plate numbers
plates = s(n) ;

% display results
fprintf('\n%10s | Plate # \n','Index')
for k=1:numel(n)
fprintf('%10d : %s\n',n(k),plates(k,:))
end


outputs:

     Index | Plate #
0 : AA-000-AA
1 : AA-001-AA
999 : AA-999-AA
1000 : AA-000-AB
675999 : AA-999-ZZ
676000 : AB-000-AA
456975999 : ZZ-999-ZZ


Variant: Note that the option to let sprintf or fprintf take care of the number to character conversion is possible. It allow to simplify the function c, but overall result in a few more bytes in this implementation (119 bytes):

c=@(x,p)mod(idivide(x,1000*26^p),26)+65 ;
s=@(n)sprintf('%c%c-%03d-%c%c\n',[c(n,3),c(n,2),mod(n,1000),c(n,1),c(n,0)]')


# C (gcc), 136106 105 bytes

#define P(i)s[i]=65+x%26;x/=26;
z;s[]=L"  -%03d-  ";f(x){z=x%1000;x/=1e3;P(9)P(8)P(1)P(0)wprintf(s,z);}


Try it online!

-7 bytes from celingcat's solution, with additional -23 inspired by it

-1 byte from ceilingcat's solution by changing the char[] to a wchar_t[] implicitly cast to int[]

Uses 0-based indexing.

Explanation/Ungolfed:

int s[] = L"  -%03d-  "; // Pre-made wide-string with dashes and ending null byte
// and wprintf directive for digits
int z;                   // Temporary variable to store the digit part
void f(int x) {
z = x % 1000;        // The digits represent x % 1000
x /= 1000;
s = 'A' + x % 26; // Place least significant letter
x /= 26;             // Divide off least significant letter
s = 'A' + x % 26; // Place second letter
x /= 26;             // Divide off second letter
s = 'A' + x % 26; // Place third letter
x /= 26;             // Divide off third letter
s = 'A' + x;      // Place fourth letter (Don't need to % 26 because x < 26 now)
wprintf(s, z); // Print finished string (with x%1000 replacing %03d)
}

• @ceilingcat Thanks! Using that idea I removed the a and b parameters from the macro and got down to 106 bytes Sep 28, 2019 at 0:39

# Kotlin, 93 bytes

{i:Int->val c={v:Int->'A'+i/v/1000%26}
""+c(17576)+c(676)+"-%03d-".format(i%1000)+c(26)+c(1)}


Try it online!

# Python 3, 161 bytes

i,t,u,v,a,c,f=int(input()),1000,676,26,ord('A'),chr,lambda x:c(a+x//v)+c(a+x%v)
m,n=i%t,i//t
e,o=n%u,n//u
print('-'.join([f(o),(3-len(str(m)))*'0'+str(m),f(e)]))
`

Try it online!