String Calculator

Assume you're writing in one method, (or whatever you call them) with 3 inputs: the first string, a character that contains a +, - or * symbol, and the second string.

Example in Java:

public String strCalc(String str1, char sym, String str2) {
//code...
}


What it should return:

str1 sym str2 ans
A     +  A   =  B
A     +  B   =  C
B     +  B   =  D
Z     +  A   =  AA
W     +  B   =  Y
A     -  A   =  ' ' (Space Character)
A     -  B   =  -A
A     -  C   =  -B
B     -  A   =  A
CA    -  A   =  BZ
A     *  A   =  A
B     *  B   =  D


Think of a one-indexed base 26. Then convert the numbers back to letters based on their position in the alphabet.

0 = ' ' (Space Character)
1 = A
2 = B
3 = C
4 = D
5 = E
6 = F
7 = G
8 = H
9 = I
10 = J
11 = K
and so on...


This is , so the shortest code in bytes not including the method declaration wins.

• Are full programs allowed? Oct 18, 2016 at 17:24
• This must be done within one method, if methods don't exist in the language you use, you may use full programs.
– Kyza
Oct 18, 2016 at 17:28
• I assume this is meant to just be math in one-based base 26, but could you clarify? Oct 18, 2016 at 17:35
• I removed division because that would simply be too tedious.
– Kyza
Oct 18, 2016 at 17:43
• Must the method be able to handle zero (space-character) and negative inputs (such as "-AB")? Oct 18, 2016 at 20:38

Jelly, 64 63 bytes

Aḃ26ịØA
O_64»0ḅ26
e”-NḤ’×Ç
³Ç;“*×-_”y⁴¤;⁵Ç¤V
¢<0”-x;¢1Ŀ¤
¢⁶¢L¤?


Not a particularly clean solution; there are no 3 argument methods in Jelly, so this is a full program.

Accepts negative inputs like "-A", "- A", " -A", ... (note however "--A" is treated as "-A")
Accepts zero inputs like "", " ", " ", ...

TryItOnline

How?

Aḃ26ịØA           - Link 1, convert integer to absolute value string: i
A                 - absolute value of i
ḃ26              - convert to bijective base 26 (a list of integers in [1,26])
ị             - index into (1-based)
ØA           - alphabet yield -> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- (note: 0 will convert to an empty string here.)

O_64»0ḅ26         - Link 2, convert an input string to a positive integer: s
O                 - cast to ordinal (vectorises)
_64              - subtract 64 from each (A->[1], B->[2], ..., AZ->[1,26], ...)
»0            - maximum of that and zero ("-" and space become zeros; vectorises)
ḅ26         - convert from base-26 to an integer (26 place values still work)

e”-NḤ’×Ç          - Link 3, convert an input string to an integer: s
”-               - literal '-'
e                 - exists in s?
N              - negate
Ḥ             - double
’            - increment (if "-" was in s we have -1, else we have 1)
×           - multiply by

³                 - first program input
Ç                - call last link (3) as a monad (value of first input as an integer)
;               - concatenate with
⁴       -     second program input
y        -     map characters
“*×-_”         -     literal "*×-_" - change "*" to "×" and "-" to "_"
;     - concatenate with
⁵    -     third program input
Ç   -     call last link (3) as a monad (value of 3rd input as integer)
V - evaluate string as Jelly code (something like "-76×5" or "3_2")

¢                 - call the last link (4) as a nilad (integer result)
<0               - less than zero?
”-             - literal '-'
x            - repeat ('-' if negative '' if positive or zero)
;           - concatenate with
¢          -     call the last link (4) as a nilad (integer result)
1Ŀ        -     call the next link (1) as a monad (as absolute string)

?            - ternary if
L              -     length
- True case (has length)
- False case (no length)
⁶                - literal ' '

• CA - A should be BZ -CA - A should be -BZ
– Kyza
Oct 18, 2016 at 19:37
• CA - A should be BZ
– Kyza
Oct 18, 2016 at 19:38
• Should all work now. Oct 18, 2016 at 21:46

Assembler x86 (32-bit) - 142 bytes

The 142 bytes are the compiled size (not the source code size, which is larger). Note that for assembler the size of the compiled code is not dependend on the compiler used but it should always be 142 bytes.

The calling convention is "_cdecl" so you can call the function from C:

const char *strCalc(const char *num1,
char operation, const char *num2, char *bufferEnd);


The function accepts negative inputs (such as "-AB") and zero (" "). However malformed inputs might crash the program!

The last argument points to the LAST byte of a buffer used to store the sring because C does not support strings without pre-allocated buffers.

The function returns the pointer to the string (somewhere in the buffer). The function may be called the following way:

#include <stdio.h>

const char *strCalc(const char *num1, char operation, const char *num2, char *bufferEnd);

main(int argc,char **argv)
{
char buf[21];
puts(strCalc(argv[1],argv[2][0],argv[3],buf+20));
}


Here is the actual function (Linux users: Replace "_strCalc" by "strCalc"):

    .globl _strCalc
.text
_strCalc:
push %ebx
push %esi
push %edi
mov 16(%esp), %esi
push %ebx
mov 28(%esp), %esi
pop %eax
# This assumes that the operation is ONLY +, * or -!
cmpb $0x2B, 20(%esp) je isPlus jb isMultiply sub %ebx, %eax jmp calcDone isPlus: add %ebx, %eax jmp calcDone isMultiply: xor %edx, %edx imul %ebx calcDone: push %eax mov 32(%esp), %edi std xor %al, %al stosb pop %eax call writeOut mov %al, (%edi) mov %edi, %eax inc %eax pop %edi pop %esi pop %ebx # Needed due to MSVCRT.DLL bug! cld ret # Write EAX to the buffer # EDI points to the last character to be # written (the terminating NUL has already been written) # Returns: EDI pointer to the first character! writeOut: test %eax, %eax jnz notZero mov$0x20, %al
stosb
ret
notZero:
jns notNegative
neg %eax
call writeOut
mov $0x2D,%al stosb ret notNegative: xor %edx, %edx dec %eax div %ecx xchg %al, %dl add$0x41, %al
stosb
xchg %al, %dl
test %eax, %eax
jnz notNegative
xchg %al, %dl
ret

# Load number from string ESI points to to EBX
# Destroys EAX, ECX, EDX
# Allows negative and zero inputs!
# Assumes syntactically correct numbers!
# Sets ECX to 26 (needed later!)
xor %ebx, %ebx
xor %eax, %eax
mov $26, %al mov %eax, %ecx nextLoad: cld lodsb and$0xDF, %al