# Parse a variable star designation

The variable star designation is an identifier for a variable star (a star that fluctuates in brightness). It consists of either a 1-2 letter code or (when the letter code is no longer sufficient) a 'V' followed by a number. This code is followed by the genitive of the star constellation the star is found in (eg. "RR Coronae Borealis", in short "RR CrB"), and each constellation has their own independent numbering.

The series of variable star designations inside one constellation is as follows:

2. Continue with RR...RZ, then use SS...SZ, TT...TZ and so on until ZZ.
3. Use AA...AZ, BB...BZ, CC...CZ and so on until reaching QZ, always omitting J in both the first and second positions.
4. After QZ (the 334th designation) abandon the Latin script and start naming stars with V335, V336, and so on (V followed by the full numeric index).

Note: The second letter is never alphabetically before the first, ie. BA for example is an invalid designation. Single letters before R are unused. J never appears in the designation.

Parse a variable star designation and return its index in the series of variable star designations!

The input is a string of just the variable star designation (omitting the constellation reference that is usually included in a full variable star designation). It can be assumed to be a valid variable star designation; validation is not part of this challenge.

Output is a number representing at what index in the series the designation is. The index is 1-based.

Test cases:

• QV => 330
• U => 4
• V5000 => 5000
• AB => 56

This is , so the shortest code wins. Standard rules and loopholes apply.

# Python 3, 121 bytes

lambda z,a='ABCDEFGHIKLMNOPQ',r='RSTUVWXYZ':int(z[1:])if z[2:]else[t+u for t in['',*r+a]for u in a+r if t<=u].index(z)-15

Try it online!

## Explanation

The list comprehension [t+u for t in['',*r+a]for u in a+r if t<=u] evaluates to these strings:

t='':   A  B  C  D  E  F  G  H  I  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z
t='R':                                                 RR RS RT RU RV RW RX RY RZ
t='S':                                                    SS ST SU SV SW SX SY SZ
t='T':                                                       TT TU TV TW TX TY SZ
t='U':                                                          UU UV UW UX UY SZ
t='V':                                                             VV VW VX VY VZ
t='W':                                                                WW WX WY WZ
t='X':                                                                   XX XY XZ
t='Y':                                                                      YY YZ
t='Z':                                                                         ZZ
t='A': AA AB AC AD AE AF AG AH AI AK AL AM AN AO AP AQ AR AS AT AU AV AW AX AY AZ
t='B':    BB BC BD BE BF BG BH BI BK BL BM BN BO BP BQ BR BS BT BU BV BW BX BY BZ
...
...
...
t='Q':                                              QQ QR QS QT QU QV QW QX QY QZ

If there are any characters past the first two (z[2:]) then the result is int(z[1:]). Otherwise (i.e. if there are only one or two characters) we look the string up in the list we created and subtract 15 from the index.

• If we may assume an upper bound on the input, it looks like you can convert this to an object method for 123: Try it online!
– xnor
Commented May 14, 2020 at 20:00
• Do you think I can get away with omitting int() and returning a string for the Vnnn case? It feels weird…
– lynn
Commented May 14, 2020 at 20:26
• It feels weird to me too. Though I remember I had a golf where someone suggested changing a string zero to a number zero in the output to handle a special case and nobody objected.
– xnor
Commented May 14, 2020 at 20:53

# JavaScript (ES6),  104 100 98  92 bytes

s=>+s.slice(1)||(n=parseInt(s,36))-((v=n/36|0)?250-v*~v/2+(n%36>18)+(v>18?v>26?360:35:v):26)

Try it online!

### How?

We first test whether removing the first character of the input string leads to a numeric value. If it does, we just return that. For instance, V5000 gives $$\5000\$$.

Otherwise, we convert the whole string from base-36 to decimal and store the result in $$\n\$$.

The index $$\i_n\$$ of the star is always less than $$\n\$$. What we want to do is find out the difference $$\d_n\$$ such that:

$$i_n=n-d_n$$

Let $$\v_n\$$ be the higher base-36 digit:

$$v_n=\left\lfloor\frac{n}{36}\right\rfloor$$

If $$\v_n=0\$$, it means that this is a single letter designation and we just need to subtract $$\d_n=26\$$ from $$\n\$$ to get the correct index (R=1, S=2, etc.).

Otherwise, we compute:

$$d_n=250+t_n+k_n+o_n$$

$$\t_n\$$ is the term reflecting the fact the designation is triangular (ZZ, YY YZ, XX XY XZ, etc.):

$$t_n={v_n+1 \choose 2}=\frac{v_n\cdot(v_n+1)}{2}$$

$$\k_n\$$ is the correction term for the missing J for the second letter:

$$k_n=\cases{0,&\text{n\bmod36\le18}\\ 1,&\text{n\bmod36>18} }$$

Finally, $$\o_n\$$ acts both as a correction term for the missing J for the first letter and as an offset for the 'wrapping' nature of the designation which goes first from RR to ZZ and then from AA to QZ:

$$o_n=\cases{v_n,&\text{v_n\le18}\\ 35,&\text{1826} }$$

# Charcoal, 41 bytes

≔…R¦[η≔Φα⁻κ⁹ζＦ﹪⁻Ｅζκ⁹ＬζＦ✂ζι⊞η⁺§ζικＩ∨⊕⌕ηθΣθ

Try it online! Link is to verbose version of code. Explanation:

≔…R¦[η

Start building up a list of designations with the single letters R to Z.

≔Φα⁻κ⁹ζ

Get the alphabet without the letter J.

Ｆ﹪⁻Ｅζκ⁹Ｌζ

Loop over each possible first letter, but offset the value so it starts at the index of R, wraps around, and stops at the index of Q.

Ｆ✂ζι

Loop over each possible second letter.

⊞η⁺§ζικ

Push the letter pair to the list of designations.

Ｉ∨⊕⌕ηθΣθ

Output the index in the list, or if not found, the embedded number.

# Pyth, 35 34 bytes

|hx-I#\J+Kr\R\[smr+dd+d\[+Kr\A\RQt

Try it online!

Uses string ranges to build a list of star designations, then finds the index of the input in that list.

Explanation

• r\R\[ is the range from R to [ (half-open range, so the range ends at Z) and r\A\R is the range from A to R

• mr+dd+d\[ maps each character $$\d\$$ of a given list to the range from $$\dd\$$ to $$\d\$$[

(eg. "S" would map to the range "SS" to "S[")

• Hence, +Kr\R\[smr+dd+d\[+Kr\A\R builds the following list:
['R',...'Z', 'RR',...'RZ', 'SS',...'SZ', 'TT',...'TZ',... 'ZZ', 'AA',... 'AZ', 'BB',... 'BZ',...'QZ']
• -I#\J filters out items that contain a J

• x ... Q gives the index of the input in that list. If the input is not in the list, -1 is returned.

• h increments that result (so if the input was not in the list, we now have 0)
• | ... t(Q) catches the Vxx case. If the previous expression evaluated to 0 (meaning the input was not in the constructed list), this returns the "tail" of the input (ie. the number after the V)

# Jelly,  23 22  20 bytes

ØAḟ”JŒċṙ280Ḋ€ḣ9;ƲiȯḊ

A full program which prints the index.

Try it online!

### How?

ØAḟ”JŒċṙ280Ḋ€ḣ9;ƲiȯḊ - Main Link: list of characters, V
ØA                   - upper-case alphabet characters
”J                - character 'J'
Œċ              - combinations with repetition = ["AA","AB",...,"AZ","BB",...]
ṙ280          - rotate left by 280 = ["RR","RS",...,"RZ","SS",..."]
Ḋ€        -   dequeue each = ["R","S",...,"Z","S",...]
ḣ9      -   head to index 9 = ["R","S",...,"Z"]
;     -   concatenate these together = ["R","S",...,"Z","RR","RS",...]
i   - first index of V in that (or 0 if not found)
Ḋ - dequeue V (i.e. "V5000" -> "5000")
ȯ  - logical OR
- implicit print

# C (gcc),  92 89  87 bytes

Saved 2 bytes thanks to @ceilingcat

Very similar to my JS answer, but without the constraint of working in base 36.

v;f(char*s){v=*s++-81;s=*s?s[1]?atoi(s):v*10+254+*s+v*~v/2-*s/74-(v>-8?v>0?334:9:v):v;}

Try it online!