# Sum of strings (UTF-16 codepoints)

Your function must accept two strings and return new string where are UTF-16 code of all symbols is the sum of UTF-16 codes of inputs symbols

• If the resulting sum is greater than 65535 (maximum UTF-16 codepoint), take the sum modulo 65536

• If there are more symbols in one string then sum with zero, codes of symbols which doesn't have pairs

For example:

• 'a' + 'b' = a(97) + b(98) = 97 + 98 = 195 => 'Ã'
• 'A' + 'B' = A(65) + B(66) = 65 + 66 = 131 => '\u0083' (No Break Here)
• 'Aa' + 'BbC' = [A(65) + B(66)][a(97) + b(98)][(0) + C(67)] => '\u0083ÃC' - \u0083 will not be displayed but it must be here so the length of result string must be 3 not 2

Test cases:

'a', 'b' --> 'Ã'

'A', 'B' --> '\u0083'

'Aa', 'BbC' --> '\u0083ÃC'

'耀', '耀' --> '\u0000' (Null character)

'Программирование', 'Programming' --> 'ѯҲҭҚҲґҩҩҡҮҥвание'


Ungolfed version (check in real time):

const updateResult = () => {
const string_1 = input1.value;
const string_2 = input2.value;
resultString = [];

for (let i = 0; i < string_1.length || i < string_2.length; ++i) {
resultString.push(
(string_1.charCodeAt(i) || 0) +
(string_2.charCodeAt(i) || 0)
);
}

resultString = String.fromCharCode(...resultString);

result.innerHTML = resultString;
resultLength.innerHTML = 'Length: ' + resultString.length;
}

updateResult();
<input id="input1" value="aA"/>
<input id="input2" value="bB"/>

<br/><br/>

<div id="result"></div>
<div id="resultLength"></div>

The shortest code in each programming language wins!

• How does the last test case have \u0083 between the other two instead of being first? Commented Feb 28, 2023 at 16:29
• Suggested tag: string Commented Feb 28, 2023 at 17:49
• @TheThonnu Added. Thank you! Commented Feb 28, 2023 at 17:55
• Are the characters guaranteed to be in Unicode Plane 0? Commented Mar 1, 2023 at 1:43
• @alephalpha All symbols will be from range [\u+0000, \u+ffff] Commented Mar 1, 2023 at 1:45

# Excel, 92 89 bytes

=CONCAT(
TOCOL(UNICHAR(MOD(MMULT(IFERROR(UNICODE(MID(A1:B1,ROW(A:A),1)),),{1;1}),4^8)),2)
)


Inputs in cells A1 and B1.

Thanks to JvdV for the 3-byte save.

• 89 Bytes =CONCAT(TOCOL(UNICHAR(MOD(MMULT(IFERROR(UNICODE(MID(A1:B1,ROW(A:A),1)),),{1,1}),4^8)),2))
– JvdV
Commented Mar 1, 2023 at 14:53
• @JvdV :-) That's sneaky! TOCOL with 2nd parameter can replace IFERROR! Commented Mar 1, 2023 at 15:01
• Would just change your {1,1} to {1;1} for English-language versions maybe. Commented Mar 1, 2023 at 15:01
• Woops, yes, that's a typo!
– JvdV
Commented Mar 1, 2023 at 15:02
• And thanks very much for taking the time to look at and improve upon my posts here. Much appreciated. On a pure byte count it's obviously near impossible to compete with the vast majority of the other languages here, but at least we can keep the Excel flag flying, for what it's worth. Commented Mar 1, 2023 at 15:11

# Vyxal, 6 bytes

C∑k₴%C


Try it Online!

How it works:

C∑k₴%C
C∑       Sum codepoints of each word
k₴%    Push 65535 and modulo by each element
C   Convert codepoints to words


# Japt, 11 bytes

Takes input as an array of 2 character arrays, outputs a single character array.

ÕËxc uG²² d


Try it

ÕËxc uG²² d     :Implicit input of 2D array
Õ               :Transpose
Ë              :Map
x             :  Sum of
c            :    Codepoints
u          :  Modulo
G         :    16
²²       :    Squared twice
d     :  Character at resulting codepoint


# Z80 machine language, 52 bytes

Null-terminated strings, addresses passed in DE and HL; output string address passed in BC. Little-endian.

D5 E5 7E 23 B6 23 EB 28 0A 7E 23 B6 23 EB 20 F4
37 E1 D5 30 03 EB C5 7E 02 23 03 B6 7E 02 23 03
20 F7 E1 1A 47 86 77 13 23 1A 4F 8E 77 13 23 78
B1 20 F2 C9


Disassembled:

f:
push de         // D5
push hl         // E5
wl:
ld a,(hl)       // 7E       // test one wchar of each
inc hl          // 23
or (hl)         // B6
inc hl          // 23
ex de,hl        // EB
jr z,fzero      // 28 0A
ld a,(hl)       // 7E
inc hl          // 23
or (hl)         // B6
inc hl          // 23
ex de,hl        // EB
jr nz,wl        // 20 F4
scf             // 37       // if we have made it here, first was shorter
fzero:
pop hl          // E1
pop de          // D5
jr nc,copy      // 30 03
ex de,hl        // EB
copy:               //          when we get here, wstrlen(hl)>wstrlen(de)
push bc         // C5
cl:
ld a,(hl)       // 7E       // copy a byte
ld (bc),a       // 02
inc hl          // 23
inc bc          // 03
or (hl)         // B6       // or in the second to see if both 0
ld a,(hl)       // 7E       // copy the second (preserves flags)
ld (bc),a       // 02
inc hl          // 23
inc bc          // 03
jr nz,cl        // 20 F7    // if either nonzero, loop again
pop hl          // E1       // put dest in hl
aloop:
ld a,(de)       // 1A
ld b,a          // 47
ld (hl),a       // 77
inc de          // 13       // *(hl++) += (b = *(de++)
inc hl          // 23
ld a,(de)       // 1A
ld c,a          // 4F
ld (hl),a       // 77
inc de          // 13
inc hl          // 23       // *(hl++) += (c = *(de++)) + cf
ld a,b          // 78
or c            // B1
jr nz,aloop     // 20 F2    // continue if b|c
ret             // C9


# Python, 89 bytes

lambda x,y:[chr(sum(map(ord,a))%4**8)for a in zip(f'{x:\0<{len(y)}}',f'{y:\0<{len(x)}}')]


Try it online!

-15 bytes thanks to @SevC_10

• Here are some improvements: 1. no need for the external map; 2. use the f-string for padding the strings to equal length; 3. use \0 for the NUL character. Try it online 89 bytes Commented Mar 1, 2023 at 13:36

# 05AB1E, 7 bytes

0ζOžH%ç


Try it online!

#### Explanation

0ζOžH%ç  # 05AB1E automatically converts the strings
# to codepoints since they are delimited by '
0ζ       # Transpose with filler 0
O      # Sum each inner list
žH    # Push 65536
%   # Mod each value by 65536
ç  # Convert back from codepoint to character

• "05AB1E automatically converts the strings to codepoints since they are in a list" Didn't even knew it did this. o.Ô Nice answer! Commented Mar 1, 2023 at 8:30
• I think the reason this works is that items and lists are evaluated by elixir, and '-delimited strings are codepoint lists in Elixir. This is different if you use " as string delimiters
– ovs
Commented Mar 1, 2023 at 11:03
• @ovs oh yeah, you're right. I didn't check that. Commented Mar 1, 2023 at 16:10

# J, 3027 25 bytes

(65536|+/@,:)&.(3 u:7&u:)


-3 thanks to ovs, and -2 more.

Attempt This Online!

(65536|+/@,:)&.(3 u:7&u:)
&.            NB. u&.v applies v to both args and u to the results
NB. then applies the inverse of v to the results of u
7&u:   NB. converts each char to a single unicode codepoint
3 u:       NB. convert string to a list of codepoints
,:               NB. stacks codepoint lists filling with 0s
+/@                 NB. then sum the columns of the resulting table
65536|                    NB. mod each sum by 65536
NB. inverse of v converts codepoints to chars

• I don't think the !.0 is necessary, that seems to be the default behaviour.
– ovs
Commented Mar 1, 2023 at 11:01
• Good catch, I was so focused on trying to get ,. to work... Commented Mar 2, 2023 at 1:59
• (65536|[+/@,:])&.(3 u:7&u:) alternate 27 Commented Mar 4, 2023 at 1:12
• Pretty sure you drop [ and ]?
– ovs
Commented Mar 4, 2023 at 8:29
• Huh, yeah. Thanks again Commented Mar 5, 2023 at 23:21

# Python 3, 76 bytes

f=lambda a,b:a and b and chr(ord(a[0])+ord(b[0])&65535)+f(a[1:],b[1:])or a+b


Try it online!

# Raku, 61 bytes

{utf16(roundrobin(@_».encode('utf16'))».sum X%4⁸).decode}


Try it online!

(The older Raku version on TIO requires a ".new" after the first "utf16" for four additional bytes.)

• @_ are the string arguments to the function.
• ».encode('utf16') encodes each of those strings as a utf16 blob object.
• roundrobin combines corresponding elements of those blobs as lists, like zip, but doesn't stop when the end of the shortest input is reached. roundrobin <1 2>, <3 4 5 6> returns (1 3), (2, 4), (5,), (6,).
• ».sum converts each of those zipped lists to its sum.
• X% 4⁸ takes each of those sums modulo 65536. (4⁸ is one byte shorter than 65536.)
• utf16 converts that list of integers to a utf16 blob.
• .decode converts that blob into a string.

# Charcoal, 37 bytes

Ｆ²⊞υＳＵＭυ⁺ι×ψ⁻Ｌ§υ¬ιＬι⭆⊟υ℅﹪⁺℅ι℅§ΣυκＸ⁴¦⁸


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

Ｆ²⊞υＳ


Input the two strings.

ＵＭυ⁺ι×ψ⁻Ｌ§υ¬ιＬι


Pad the shorter to the length of the longer with null bytes.

⭆⊟υ℅﹪⁺℅ι℅§ΣυκＸ⁴¦⁸


Pairwise add the character codes of the two strings, reduce module 4⁸, then convert back to characters.

# Factor, 38 bytes

[ 0 pad-longest [ + 65536 mod ] 2map ]


Try it online!

• 0 pad-longest pad the shorter of two sequences with 0s until it is the same length as the longer one
• [ ... ] 2map map over two sequences with a binary function
• + 65536 mod add the code points together modulo 65536

# Brachylog, 15 bytes

ạᵐz₁+ᵐ%₆₅₅₃₆ᵐ~ạ


Try it online!

### Explanation

ạᵐ               Map to codes
z₁             Zip without cycling
+ᵐ           Map sum
%₆₅₅₃₆ᵐ    Map mod 65536
~ạ  Codes to string


# C (gcc) with -fwide-exec-charset=UTF16LE, 78 bytes

Takes inputs in UCS-2 (UTF-16LE) encoding and outputs in UCS-2 (UTF-16LE) encoding. TIO and shells don't seem to like UTF-16: running this from an actual machine and redirecting the output gives the correct results.

Output (in KWrite, UTF-16 encoding):

f(i,j,k)short*i,*j;{for(;*i|*j;*i&&i++,*j&&j++)printf("%2\$c%c",k>>8,k=*i+*j);}


Try it online!

# JavaScript, 91 bytes (tsh's method)

With recursion

(a,b)=>(g=i=>a[i]?String.fromCharCode(a[c='charCodeAt'](i)+~~b[c](i))+g(i+1):b.slice(i))(0)


Try it:

f=(a,b)=>(g=i=>a[i]?String.fromCharCode(a[c='charCodeAt'](i)+~~b[c](i))+g(i+1):b.slice(i))(0)

const inputHandler = () => {
resultString = f(input1.value, input2.value)

result.innerHTML = resultString;
resultLength.innerHTML = 'Length: ' + resultString.length;
}

inputHandler();
<input id="input1" value="aA"/>
<input id="input2" value="bB"/>

<br/><br/>

<div id="result"></div>
<div id="resultLength"></div>

# JavaScript, 97 bytes

Without recursion

(a,b)=>String.fromCharCode(...[...a].map((s,i)=>(g=c=>c.charCodeAt(j=i)|0)(a)+g(b)))+b.slice(j+1)


Try it:

f=(a,b)=>String.fromCharCode(...[...a].map((s,i)=>(g=c=>c.charCodeAt(j=i)|0)(a)+g(b)))+b.slice(j+1)

const inputHandler = () => {
resultString = f(input1.value, input2.value)

result.innerHTML = resultString;
resultLength.innerHTML = 'Length: ' + resultString.length;
}

inputHandler();
<input id="input1" value="aA"/>
<input id="input2" value="bB"/>

<br/><br/>

<div id="result"></div>
<div id="resultLength"></div>

• a=>b=>(g=i=>a[i]?String.fromCharCode(a[c='charCodeAt'](i)+~~b[c](i))+g(i+1):b.slice(i))(0)
– tsh
Commented Mar 2, 2023 at 5:51

# CJam, 9 bytes

z::i::+:c


Try it online!

# Explanation

z::i::+:c # a function taking an array with two strings [x y]
z         # zip; transpose rows with columns (i.e, ["Aa" "BbC"] => ["AB" "ab" "C"]
::i      # map int convert to all values
::+   # map add to all values, effectively summing each
:c # map each summed value to chars