10
\$\begingroup\$

This is an exact inverse of the question Convert to Spoken Binary. This introduction is copied from there.

Introduction

In the video the best way to count, binary is proposed as the best system of counting numbers. Along with this argument is a proposal on how to say numbers in this system. First, we give names to each "double power of two", \$2^{2^n}\$ for each \$n\$.

number = symbol = spoken
============================
2^0    = 1      = "one"
2^1    = 2      = "two"
2^2    = 4      = "four"
2^4    = H      = "hex"
2^8    = B      = "byte"
2^16   = S      = "short"
2^32   = I      = "int"
2^64   = L      = "long"
2^128  = O      = "overlong"
2^256  = P      = "byteplex"

Then, to get from a number to its spoken binary, we

  1. Take its (big-endian) bit string and break off bits from the end equal to the number of zeros in the largest double power of two less than or equal to the number.

  2. Use the name for the corresponding double power of two in the middle, and recursively name the left and right parts through the same procedure. If the left part is one, it is not spoken, and if the right part is zero, it is not spoken.

This system is similar to how we normally read numbers: 2004 -> 2 "thousand" 004 -> "two thousand four".

You can find examples of this procedure in the linked question.

To parse a number in spoken binary, do the opposite of the above, i.e.

  1. Find the largest double power of two in the spoken binary (it is unique).

  2. Recursively parse the sections to the left and the right through the same procedure (assuming one on left and zero on right if either are empty), and compute left * middle + right.

This system is similar to how we normally parse numbers: "two thousand four" -> 2 * 1000 + 4 -> 2004.

As an example,

"2H214"
"2" * 16 + "214"
2 * 16 + "21" * 4 + 0
2 * 16 + (2 + 1) * 4 + 0
44

Challenge

Your program must take a string of symbols for the spoken binary of a positive integer \$n\$ as input and output the integer it represents in decimal.

While numbers under \$2^{512}\$ are expressible in this system, you only need to handle integers up to and including \$2^{32}\$ = I, and as such, do not need to consider L, O, or P. You only need to consider valid spoken binary strings; you do not need to handle cases like HH, 1H, H44, 4121S etc.

Standard loopholes are forbidden. As this is , shortest program wins.

Example Input and Output

1 -> 1
2 -> 2
21 -> 3
4 -> 4
41 -> 5
42 -> 6
421 -> 7
24 -> 8
241 -> 9
242 -> 10
2421 -> 11  
214 -> 12   
H241 -> 25   
2H214 -> 44   
42H4 -> 100  
21B2142H24 -> 1000 
21421H21421B21421H21421S21421H21421B21421H21421 -> 4294967295
I -> 4294967296

If you need any more test cases, the answers to the linked question can help. Here is one TIO (Credit to @Nick Kennedy).

\$\endgroup\$
1
  • 1
    \$\begingroup\$ When I first read the title, I thought it would be like this xkcd. \$\endgroup\$
    – Bbrk24
    Commented Dec 25, 2023 at 14:51

6 Answers 6

3
\$\begingroup\$

Ruby, 91 88 bytes

->(s){s.each_char.reduce(0){|x,a|v=2**(2**("124HBSI".index a)/2);x%v>0?x+x%v*(v-1):x+v}}

Try it online!

I'm only posting this one because I didn't see one remainder based approach. Basically, for each digit, we decide if we're adding it as it is, or using it as a multiplier. If we've seen something smaller than the current digit, then whatever is smaller should be multiplied, else we just add the digit.

Thanks @Neil for -3 bytes!

\$\endgroup\$
1
  • \$\begingroup\$ 88 bytes: Try it online!, but nice first answer! \$\endgroup\$
    – Neil
    Commented Dec 28, 2023 at 17:30
2
\$\begingroup\$

JavaScript (Node.js), 78 76 bytes

f=(x,i=6,z)=>i--?x.split('24HBSI'[i]).map(s=>z=(z|z<1)*2**2**i+f(s,i))&&z:+x

Try it online!

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

Charcoal, 34 bytes

⊞υ⮌SFISBH42≔ΣEυ…⊞OE⪪κι∨μIν0²υI⍘⮌υ²

Attempt This Online! Link is to verbose version of code. Will produce values up to 18446744073709551615. Explanation:

⊞υ⮌S

Start with the reverse of the input in a single piece.

FISBH42

Work down from the highest double power of two to the lowest.

≔ΣEυ…⊞OE⪪κι∨μIν0²υ

Split each piece into two, defaulting the first piece to 0 and the second piece to 1, but if the split only resulted in one piece then pad it with a 0 piece. Examples: 2 splits on 2 to give two empty strings, so the first becomes 0 and the second 1, representing 10 in binary; 21 splits on 2 to give 1 and an empty string, the latter becoming 1, representing 11 in binary; 1 splits on 2 to give 1, which is padded with a 0, representing 01 in binary.

I⍘⮌υ²

The reversed list is now a list of binary digits so convert it to decimal.

A port of @Pufe's Ruby answer is also 34 bytes:

≔⁰θFESX²÷X²⌕124HBSIι²≧⁺∨×﹪θι⊖ιιθIθ

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

≔⁰θ

Start with zero.

FESX²÷X²⌕124HBSIι²

Map the characters of the input string to the double powers of 2 and loop over the results.

≧⁺∨×﹪θι⊖ιιθ

Add on the current value modulo the current power multiplied by one less than the current power, unless that is 0, in which case just add on the current value.

Iθ

Output the final result.

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

Jelly, 26 bytes

W“ISBH42”ṣȯ"JŻƊṫ-ʋ€Ẏ¥ƒFOḂḄ

A monadic link that is called as a monad with a spoken binary string argument and returns an integer.

The test suite takes a list of integers, uses my answer to the companion challenge to make spoken binary and then converts it back.

Inspired by @Neil’s Charcoal answer so please be sure to upvote that one too!

Explanation

W“ISBH42”ṣȯ"JŻƊṫ-ʋ€Ẏ¥ƒFOḂḄ­⁡​‎‎⁡⁠⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‎⁡⁠⁢⁢⁡‏⁠‎⁡⁠⁢⁢⁢‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁡⁢‏⁠‎⁡⁠⁢⁡⁣‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁢⁡​‎⁠⁠‎⁡⁠⁤⁣‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁣⁣‏⁠‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏‏​⁡⁠⁡‌⁢⁣​‎⁠‎⁡⁠⁤⁢‏‏​⁡⁠⁡‌⁢⁤​‎‎⁡⁠⁤⁤‏⁠‎⁡⁠⁢⁡⁡‏‏​⁡⁠⁡‌⁣⁡​‎‎⁡⁠⁢⁡⁤‏‏​⁡⁠⁡‌⁣⁢​‎‎⁡⁠⁢⁢⁣‏‏​⁡⁠⁡‌⁣⁣​‎‎⁡⁠⁢⁢⁤‏‏​⁡⁠⁡‌⁣⁤​‎‎⁡⁠⁢⁣⁡‏‏​⁡⁠⁡‌⁤⁡​‎‎⁡⁠⁢⁣⁢‏‏​⁡⁠⁡‌­
W                           # ‎⁡Wrap in a list
 “ISBH42”           ¥ƒ      # ‎⁢Reduce using the wrapped spoken binary string as the starting argument and each of "ISBH42" in turn as the right argument using the following dyadic chain:
                 ʋ€         # ‎⁣- For each list in the list of lists:
         ṣ                  # ‎⁤  - Split with the current character (from ISBH42); will return a list of either one or two pieces, either of which may be empty
              Ɗ             # ‎⁢⁡  - Following as a monad:
          ȯ"J               # ‎⁢⁢    - Or with the list indices (will replace empty pieces in the first and second position with 1 and 2 respectively)
             Ż              # ‎⁢⁣    - Prepend zero
               ṫ-           # ‎⁢⁤  - Take the last two
                   Ẏ        # ‎⁣⁡- Join outer lists
                      F     # ‎⁣⁢Flatten
                       O    # ‎⁣⁣Convert to Unicode code points (will convert "1" to 49 and leave the existing 1s and 2s alone)
                        Ḃ   # ‎⁣⁤Mod 2
                         Ḅ  # ‎⁤⁡Unitary (convert from base 2)
💎

Created with the help of Luminespire.

Original answer, Jelly, 41 bytes

>oḊ$k⁸ṣȯ"1,0Fæ.ʋċ¡€F
“24HBSI”iⱮ’2*2*ḞṢçƒ$

A pair of links that is called as a monad with a spoken binary string argument and returns an integer (wrapped in a length 1 list). When called as a full program will print the integer implicitly.

In brief this works like this:

  1. Convert from spoken binary digits to the relevant powers of 2 (e.g. B -> 256)
  2. Work up through each digit in ascending order; find sublists of between 1 and 3 adjacent integers which are not greater than the relevant digit (e.g. 3, 4, 1 if the current digit is 2).
  3. Within each sublist, multiply the current digit by the prefix if there is one (or by 1 if none) and add any suffix if there is one. So for the example above, 3, 4, 1 becomes 13.
  4. Continue until all of the digits have been used (and so we have a single final integer result).
\$\endgroup\$
1
\$\begingroup\$

Retina, 127 125 bytes

21
3
(?<!\d)[4H]|(?<![\dH])B|^S
1$&
I
1SS
S
BB
(\d)4(\d?)
$.($1*4*_$2*
(\d+)H(\d*)
$.($1*16*_$2*
+`(\d+)B(\d*)
$.($1*256*_$2*

Try it online! Link is to test suite that converts the first number on each line. Explanation:

21
3

2 always has an implicit 1 preceding it. If it also has a 1 following it, that's then 3.

(?<!\d)[4H]|(?<![\dH])B|^S
1$&

Put in explicit 1s in places that need them.

I
1SS

Special-case I as we only need to support a lone I. (Although this will actually work for numbers up to but not including IS.)

S
BB

Change S to BB as we can multiply by 256 twice without ambiguity. (See below.)

(\d)4(\d?)
$.($1*4*_$2*

For each 4, multiply the digit before by 4 and add any digit after. Conveniently after this stage all the decimal digits are now part of the computation rather than the input.

(\d+)H(\d*)
$.($1*16*_$2*

For each H, multiply the number before by 16 and add any number after.

+`(\d+)B(\d*)
$.($1*256*_$2*

For each B, multiply the number before by 256 and add any number after. Examples for multiple Bs:

  • S11BB1256B165537
  • SB11BB1B1256B25765793
  • BSB11BBB1B1256BB25765536B25716777473
  • B1SB11B1BB1B1257BB25765792B25716843009.
\$\endgroup\$
1
\$\begingroup\$

APL(Dyalog Unicode), 57 5547 bytes SBCS

{⍵≡⍬:0⋄⍵(∇⍤↓+⌷×1⌈∘∇¯1↓↑)⍨⊃⍒⍵}2*∘⌊2*6-'ISBH42'∘⍳

Try it on APLgolf!

-8 bytes thanks to att.

Explanation

{⍵≡⍬:0⋄⍵(∇⍤↓+⌷×1⌈∘∇¯1↓↑)⍨⊃⍒⍵}2*∘⌊2*6-'ISBH42'∘⍳­⁡​‎⁠⁠⁠⁠⁠⁠⁠‎⁡⁠⁣⁢⁢‏⁠‎⁡⁠⁣⁢⁣‏⁠‎⁡⁠⁣⁢⁤‏⁠‎⁡⁠⁣⁣⁡‏⁠‎⁡⁠⁣⁣⁢‏⁠‎⁡⁠⁣⁣⁣‏⁠‎⁡⁠⁣⁣⁤‏⁠‎⁡⁠⁣⁤⁡‏⁠‎⁡⁠⁣⁤⁢‏⁠‎⁡⁠⁣⁤⁣‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣⁡⁤‏⁠‎⁡⁠⁣⁢⁡‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁣⁡⁢‏⁠‎⁡⁠⁣⁡⁣‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁤⁢‏⁠‎⁡⁠⁢⁤⁣‏⁠‎⁡⁠⁢⁤⁤‏⁠‎⁡⁠⁣⁡⁡‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢⁤⁢‏⁠‎⁡⁠⁢⁤⁣‏⁠‎⁡⁠⁢⁤⁤‏⁠‎⁡⁠⁣⁡⁡‏⁠‎⁡⁠⁣⁡⁢‏⁠‎⁡⁠⁣⁡⁣‏⁠‎⁡⁠⁣⁡⁤‏⁠‎⁡⁠⁣⁢⁡‏⁠‎⁡⁠⁣⁢⁢‏⁠‎⁡⁠⁣⁢⁣‏⁠‎⁡⁠⁣⁢⁤‏⁠‎⁡⁠⁣⁣⁡‏⁠‎⁡⁠⁣⁣⁢‏⁠‎⁡⁠⁣⁣⁣‏⁠‎⁡⁠⁣⁣⁤‏⁠‎⁡⁠⁣⁤⁡‏⁠‎⁡⁠⁣⁤⁢‏⁠‎⁡⁠⁣⁤⁣‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁢⁣​‎‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁢⁤​‎‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁣⁡​‎⁠‎⁡⁠⁢⁣⁣‏⁠‎⁡⁠⁢⁣⁤‏‏​⁡⁠⁡‌⁣⁢​‎‎⁡⁠⁢⁣⁢‏‏​⁡⁠⁡‌⁣⁣​‎‎⁡⁠⁢⁣⁢‏⁠‎⁡⁠⁢⁣⁣‏⁠‎⁡⁠⁢⁣⁤‏‏​⁡⁠⁡‌⁣⁤​‎‎⁡⁠⁢⁤‏‏​⁡⁠⁡‌⁤⁡​‎‎⁡⁠⁣⁡‏⁠‎⁡⁠⁢⁢⁤‏⁠‎⁡⁠⁢⁣⁡‏‏​⁡⁠⁡‌⁤⁢​‎‎⁡⁠⁢⁢⁣‏‏​⁡⁠⁡‌⁤⁣​‎‎⁡⁠⁢⁡⁤‏⁠‎⁡⁠⁢⁢⁡‏⁠‎⁡⁠⁢⁢⁢‏‏​⁡⁠⁡‌⁤⁤​‎‎⁡⁠⁢⁡⁣‏‏​⁡⁠⁡‌⁢⁡⁡​‎‎⁡⁠⁤⁤‏⁠‎⁡⁠⁢⁡⁡‏⁠‎⁡⁠⁢⁡⁢‏‏​⁡⁠⁡‌⁢⁡⁢​‎‎⁡⁠⁤⁢‏⁠‎⁡⁠⁤⁣‏‏​⁡⁠⁡‌⁢⁡⁣​‎‎⁡⁠⁤⁡‏‏​⁡⁠⁡‌⁢⁡⁤​‎‎⁡⁠⁣⁤‏‏​⁡⁠⁡‌⁢⁢⁡​‎‎⁡⁠⁣⁢‏⁠‎⁡⁠⁣⁣‏‏​⁡⁠⁡‌­
                                     'ISBH42'∘⍳  ⍝ ‎⁡‎⁡indices of input in 'ISBH42'
                                   6-            ⍝ ‎⁢subtract from 6
                                 2*              ⍝ ‎⁣2 to that power
                             2*∘⌊                ⍝ ‎⁤2 to floor of that
                             2*∘⌊2*6-'ISBH42'∘⍳  ⍝ ‎⁢⁡converts the symbols to numbers
 ⍵≡⍬:                                            ⍝ ‎⁢⁢‎⁢⁣if passed empty vector:
     0                                           ⍝ ‎⁢⁣return 0
      ⋄                                          ⍝ ‎⁢⁤else:
                          ⍒⍵                     ⍝ ‎⁣⁡indices to sort descending
                         ⊃                       ⍝ ‎⁣⁢first
                         ⊃⍒⍵                     ⍝ ‎⁣⁣index of maximum
       ⍵                                         ⍝ ‎⁣⁤input vector
        (              )⍨                        ⍝ ‎⁤⁡reverse the left and right arguments
                      ↑                          ⍝ ‎⁤⁢take vector up to the max value
                   ¯1↓                           ⍝ ‎⁤⁣drop the last element
                  ∇                              ⍝ ‎⁤⁤apply this dfn
               1⌈∘                               ⍝ ‎⁢⁡⁡max with 1
             ⌷×                                  ⍝ ‎⁢⁡⁢times the max value (via indexing)
            +                                    ⍝ ‎⁢⁡⁣plus
           ↓                                     ⍝ ‎⁢⁡⁤drop vector up to and including max value
         ∇⍤                                      ⍝ ‎⁢⁢⁡apply this dfn
💎

Created with the help of Luminespire

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 47 bytes \$\endgroup\$
    – att
    Commented Dec 25, 2023 at 9:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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