Calculate the binary split sum of a word

Take a string, s containing printable ASCII-characters as input, and output its "binary split sum". Need an explanation?

How do you get the binary split sum?

We'll use the string A4 as an example in the following explanation.

• Convert the characters to binary, treating each letters as a 7-bit ASCII character

A -> ASCII 65 -> 1000001
4 -> ASCII 52 -> 0110100

• Concatenate the binary numbers into a new binary number

A4 -> 1000001 & 0110100 -> 10000010110100

• Split the new binary number into chunks, where no 1 can have a 0 to its left. You should not split consecutive 1s.

10000010110100 -> 100000, 10, 110, 100

• Convert these binary numbers to decimal

100000, 10, 110, 100 -> 32, 2, 6, 4

• Take the sum of these numbers:

32 + 2 + 6 + 4 = 44

So, the output for the string A4 should be 44.

Test cases:

a
49

A4
44

codegolf
570

Hello, World!
795
• I think this would have been a nicer challenge without the ASCII conversion step, just taking the (decimal) number after step 2 as input. – xnor May 14 '17 at 20:37
• Well, 8372 actually. – xnor May 14 '17 at 20:40
• @xnor, you might be right, and it would be cleaner. I had fun solving this in Octave though, and I hope others will enjoy solving it too :) – Stewie Griffin May 14 '17 at 20:42

Python 2, 8681 76 bytes

-5 bytes thanks Adnan
-5 bytes thanks xnor

s=0
for c in input():s=s*128+ord(c)
print eval(bin(s).replace('01','0+0b1'))

Try it online!

for c in input():s=s*128+ord(c) to do the ASCII conversion numerically, where *128 is used to left shift s 7 times (steps 1 and 2)
eval(('0'+new_bin).replace('01','0+0b1')) to split and sum (steps 3, 4 and 5)

Jelly, 13 bytes

Oḅ128BŒg;2/ḄS

Try it online!

How it works

Oḅ128BŒg;2/ḄS  Main link. Argument: s (string)

O              Ordinal; map characters to their code points.
ḅ128          Unbase 128; convert the resulting list from base 128 to integer.
B         Binary; Convert the resulting integer to base 2.
Œg       Group consecutive, equal bits.
;2/    Concatenate all non-overlapping pairs.
Ḅ   Unbinary; convert from base 2 to integer.
S  Take the sum.
• I've missed that trick of base conversion before. – Jonathan Allan May 14 '17 at 21:45
• Ah, nice trick indeed! – Adnan May 15 '17 at 4:30

MATL, 14 bytes

YB!'1+0*'XXZBs

Try it online!

Explanation

Consider input 'A4' as an example.

YB        % Implicit input. Convert to binary using characters '0' and '1'.
% Gives a char matrix, where each row corresponds to a number
% STACK: ['1000001'; '0110100']
!         % Transpose. This is necessary because MATL uses column-major
% order when linearizing a matrix into a vector
% STACK: ['10'; '01'; '01'; '00'; '01'; '00'; '10']
'1+0*'    % Push this string: regexp pattern
% STACK: ['10'; '01'; '01'; '00'; '01'; '00'; '10'], '1+0*'
XX        % Regexp. Linearizes the first input into a row (in column-major
% order), and pushes a cell array of substrings that match the
% pattern given by the second input
% STACK: {'100000'; '10'; 110'; '100'}
ZB        % Convert each string into a decimal number. Gives numeric vector
% STACK: [32; 2; 6; 4]
s         % Sum. Implicitly display
% STACK: 44

05AB1E, 18 bytes

Code:

Çžy+b€¦JTR021:2¡CO

Explanation:

Ç                   # Take the ASCII value of each character
žy+                # Add 128 to each value (to pad each with enough zeros)
b               # Convert to binary
€¦             # Remove the first character
J            # Join the array
TR021:      # Replace 01 by 021
2¡    # Split on the number 2
C   # Convert from binary to decimal
O  # Sum them all up

Uses the 05AB1E encoding. Try it online!

05AB1E, 14 bytes

Çžy+b€¦Jγ2ôJCO

A port of my Jelly answer, using the 128 offset from Adnan's 05ab1e answer (rather than the 256 in the Jelly answer I wrote).

Try it online!

How?

Çžy+b€¦Jγ2ôJCO
Ç              - to ordinals
žy            - literal 128
b          - to binary
€         - for each
¦        -   dequeue
J       - join
γ      - group into chunks of equal elements
ô    - split into chunks of
2     - literal 2
J   - join
C  - from binary
O - sum

JavaScript (ES6), 97 92 bytes

s=>eval(s.replace(/./g,c=>(128+c.charCodeAt()).toString(2).slice(1)).replace(/1+/g,'+0b$&')) Edit: Saved 5 bytes with some help from @ConorO'Brien. • My own solution was 97 bytes, too: s=>eval([...s].map(e=>(e.charCodeAt()+128).toString(2).slice(1)).join.replace(/1+0*/g,'+0b$&')) You can use my replace method to save a byte, I think – Conor O'Brien May 14 '17 at 22:11
• @ConorO'Brien More than a byte, I think! – Neil May 14 '17 at 23:03
• Oo, n​i​c​e :​D – Conor O'Brien May 14 '17 at 23:07

Japt, 18 12 bytes

c_¤ùT7Ãò< xÍ
c_           // Firstly, take the input and map over it as charcodes.
¤          // Take the binary representation of each item
ùT7       // and left-pad it with zeroes to standardize the items.
Ã      // After all of the above,
ò<    // partition the result where ever a 0 precedes a 1.
xÍ // Then sum the numbers from base 2.

Takes input as a single string.
I also tried out the 128 or 256 addition used by other answers, but 0-padding was shorter to use.

Shaved off a whole whopping 6 bytes thanks to ETHproductions and Oliver.

Try it out here.

• You can use more auto-functions here: òÈ<YÃ can be ò< (with trailing space), and Ën2Ãx can be xn2. You can also use T in place of 0 to save on the comma. (Also, feel free to join us in the Japt chatroom if you ever have questions or would like help with golfing :-) ) – ETHproductions Apr 6 '18 at 15:05
• @ETHproductions Thanks again, especially for the T trick, didn't know you could (ab)use variables for that, that's very handy. The auto-function xn2 looks a bit weird when compiled, x("n", 2), so I think it will still take a bit before I fully understand the logic behind them. With your help, the Japt solution is now tied for the first place with the Jelly answer. – Nit Apr 6 '18 at 19:11
• ETHproductions recently made a shortcut for n2 : Í. It hasn't hit TIO yet, but you can use it here: ethproductions.github.io/japt/?v=1.4.5&code=Y1+k+VQ3w/… – Oliver Apr 6 '18 at 20:25
• @Oliver Wow, that's very bleeding edge, that isn't even covered in the interpreter shortcuts reference yet. Thanks a lot! – Nit Apr 7 '18 at 8:03

Jelly, 16 15 bytes

-1 byte thanks to Dennis (no need to flatten by 1 when a full flatten is fine - replace ;/ with F)

O+⁹Bṫ€3FŒg;2/ḄS

Try it online!

How?

O+⁹Bṫ€3FŒg;2/ḄS - Main link: list of characters, s    e.g. "A4"
O               - cast to ordinal (vectorises)        [65,52]
⁹             - literal 256
+              - add (vectorises)                    [321, 308]
B            - convert to binary (vectorises)      [[1,0,1,0,0,0,0,0,1],[1,0,0,1,1,0,1,0,0]]
ṫ€3         - tail €ach from index 3              [[1,0,0,0,0,0,1],[0,1,1,0,1,0,0]]
F        - reduce with concatenation           [1,0,0,0,0,0,1,0,1,1,0,1,0,0]
Œg      - group runs of equal elements        [,[0,0,0,0,0],,,[1,1],,,[0,0]]
;2/   - pairwise reduce with concatenation  [[1,0,0,0,0,0],[1,0],[1,1,0],[1,0,0]]
Ḅ  - convert from binary (vectorises)    [32,2,6,4]
S - sum                                 44
• ;/ can be replaced with F. – Dennis May 14 '17 at 21:32

PHP, 116 Bytes

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);$t=mb_split("(?<=0)(?=1)",$r);echo array_sum(array_map(bindec,$t));

Online Version

PHP, 117 Bytes

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);$t=preg_split("#0\K(?=1)#",$r);echo array_sum(array_map(bindec,$t));

Try it online!

PHP, 120 Bytes

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);preg_match_all("#1+0+#",$r,$t);foreach($tas$b)$s+=bindec($b);echo$s;

Try it online!

or

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);preg_match_all("#1+0+#",$r,$t);echo array_sum(array_map(bindec,$t));

Pyth, 21 bytes

It's too long...

siR2:.BiCMQ128"1+0+"1

Test suite.

[F#], 249 245 bytes

open System
let rec c a=function|[]->[a]|'0'::'1'::y->(a+"0")::(c""('1'::y))|x::y->c(a+string x)y
let x i=c""(String.Join("",(Seq.map(fun c->Convert.ToString(int c,2).PadLeft(7,'0'))i))|>Seq.toList)|>Seq.map(fun c->Convert.ToInt32(c,2))|>Seq.sum

Try it online!

Note: the version on tio.run has "open System" in the header, I've added its count to the code above. I'm not sure what the rules are on imports.

Ungolfed

let rec convert acc = function
| [] -> [acc]
| '0'::'1'::xs -> (acc + "0") :: (convert "" ('1'::xs))
| x::xs -> convert (acc + string x) xs

let calculateSum input =
let binary = Seq.map (fun x -> Convert.ToString(int x, 2).PadLeft(7, '0')) input

String.Join("", binary)
|> Seq.toList
|> convert ""
|>Seq.map (fun x -> Convert.ToInt32(x, 2))
|>Seq.sum
• if open System is the same as C#s using System; then yes you need to include it in the count. If you can do it in F# you could fully qualify whatever the System is for . For example, in C# System.Console... instead of using System;Console... – TheLethalCoder May 15 '17 at 16:27
• @TheLethalCoder It is the same, yes. Also, thanks for clarifying this :) I opted for the "open.." version because it's not only String, but also Convert that live in that namespace. – Brunner May 15 '17 at 17:17

Perl 6, 62 bytes

{sum map {:2(~$_)},.comb».ord».fmt('%07b').join~~m:g/11*0*/} J, 34 bytes [:+/@(,#.;.1~1,1=2#.\,)(7#2)#:3&u: Try it online! Explanation [:+/@(,#.;.1~1,1=2#.\,)(7#2)#:3&u: Input: array of characters S 3&u: Get ASCII values of each character (7#2) Array with 7 copies of the value 2 #: Convert each value to a base 2 array with length 7 [: ( ) Operate on those binary values , Flatten it 2 \ For each infix of size 2 #. Convert it to decimal from binary 1= Test each value for equality to 1 1, Prepend a 1 , The flattened binary values ;.1~ Chop that at each occurrence of a 1 #. Convert each chop from binary to decimal +/@ Reduce by addition mathematica 193 bytes f=FromDigits;l=Flatten;(S=Split@l@Table[PadLeft[IntegerDigits[ToCharacterCode@#,2][[k]],7],{k,StringLength@#}];Plus@@Table[f[RealDigits@f@Join[S[[i]],S[[i+1]]],2],{i,1,Length@S-1,2}]+Last@l@S)& • You can save 7 bytes by doing f=FromDigits;l=Flatten; at the start, and then replacing all instances of those two functions with f and l. – numbermaniac May 15 '17 at 7:37 J, 40 bytes +/>#.&.>(1,}.|.1 0 E.|.b)<;.1 b=.,#:a.i. usage: +/>#.&.>(1,}.|.1 0 E.|.b)<;.1 b=.,#:a.i.'A4' returns 44 Clojure, 150 bytes #(loop[[c & C](for[i % j[64 32 16 8 4 2 1]](mod(quot(int i)j)2))p 0 r 0 R 0](if c(if(=(dec c)p 0)(recur C c 1(+ R r))(recur C c(+(* 2 r)c)R))(+ R r))) Well I was hoping the conversion from ASCII to bytes was shorter than this. The actual loop body is quite short, using r to accumulate the current result and R to accumulate the total result. If the previous bit p is 0 and the current bit c is 1 then we split a new chunk and accumulate to R, otherwise we update the r and keep R as it was. Python 123 bytes lambda w:sum(map(lambda x:int(x,2),"".join(map(lambda x:bin(ord(x))[2:].zfill(7),list(w))).replace("01","0:1").split(":"))) Updated, thanks to Martin Ender. • Welcome to PPCG! All answers need to be either full programs or callable functions (as opposed to snippets where the input is stored in a hardcoded variable). The function can be unnamed, though, so including a lambda w: would be enough to make your answer valid. – Martin Ender Mar 28 '18 at 21:51 • Sorry, I probably didn't phrase that well. Your edit is still invalid because a) the input is hardcoded, b) If this is a full program, it doesn't actually print the result. For a full program you'd have to read the input from standard input or a command-line argument, and print the result to standard output. That's why I said it's probably easiest if you submit it as a function by adding lambda w:. – Martin Ender Mar 30 '18 at 10:22 • Ohhh, Ok, i get it, it would be enough like this: f=lambda w:sum(map(lambda x:int(x,2),"".join(map(lambda x:bin(ord(x))[2:].zfill(7),list(w))).replace("01","0:1").split(":"))) – ShadowCat Apr 4 '18 at 17:15 • yep, that's valid. You don't even need the f=, because we allow unnamed functions (unless you reference the function name for recursive calls). – Martin Ender Apr 4 '18 at 21:01 K (oK), 31 bytes Solution: +/2/'_[;x]&x&~~':x:,/(7#2)\'i$

Try it online!

Examples:

+/2/'_[;x]&x&~~':x:,/(7#2)\'i$,"a" 49 +/2/'_[;x]&x&~~':x:,/(7#2)\'i$"A4"
44
+/2/'_[;x]&x&~~':x:,/(7#2)\'i$"codegolf" 570 +/2/'_[;x]&x&~~':x:,/(7#2)\'i$"Hello, World!"
795

Explanation:

Convert to ASCII values, convert to 7-bit binary, flatten, find where differs, and against original list to find where 1s differ. Cut at these indices, convert back to decimal and sum up:

+/2/'_[;x]&x&~~':x:,/(7#2)\'i$/ the solution `i$ / convert to integer
(7#2)      / draw from 2, 7 times => 2 2 2 2 2 2 2
\'    / decode each (convert to binary)
,/           / flatten
x:             / save as x
~~':               / not-not-each previous (differ)
&                   / and with
x                    / x
&                     / indices where true
_[;x]                      / projection, cut x at ...
2/'                           / encode each (convert from binary)
+/                              / sum up

Bonus

Managed a 31 byte version in K4 too, but as there's no TIO for it I'm posting my oK solution.

+/2/:'_[;x]@&x&~~':x:,/1_'0b\:'

APL (Dyalog), 30 bytes

{+/2⊥¨(1∘+⊆⊢)∊¯7↑¨2⊥⍣¯1¨⎕UCS⍵}

Try it online!

How?

⎕UCS⍵ - Unicodify

2⊥⍣¯1¨ - encode each in binary

¯7↑¨ - and pad to the left with zeros to 7 places

- flatten

1∘+⊆⊢ - partition by self increased by one

2⊥¨ - decode each from binary

+/ - sum