# Write a Morse Calculator

Write a program or function that takes a mathematical expression in Morse code as input, and returns the solution in Morse code.

Valid operations are plus: + and minus: _ (underscore). You can assume you will only receive non-negative integer input, and that the result will be non-negative.

The expression will contain at least two terms, and maximum ten terms. There won't be two adjacent operators i.e. .----+_-...., and there won't be parentheses.

Digits are seperated by single spaces. You can choose to have the operators separated from the numbers by a single space on each side (see examples).

The Morse equivalent for the digits 0-9 are:

0  -----
1  .----
2  ..---
3  ...--
4  ....-
5  .....
6  -....
7  --...
8  ---..
9  ----.


Examples:

Input
Output

.----+.----  (1+1=2) Optional input: .---- + .----
..---

-...._...--  (6-3=3) Optional input: -.... _ ...--
...--

..---_...--+..--- (2-3+2=1)
1

..---+...--_....-+---.._.....  (2+3-4+8-5=4)
....-

.---- ..---_-....+...-- ...--  (12-6+33=39)
...-- ----.

----. -----+----.+..--- ----._..... .....+---..+-...._.----+----.+----._..--- -----  (90+9+29-55+8+6-1+9+9-20=84)
---.. ....-


Standard rules regarding I/O formats etc. apply. A few trailing spaces, and a single newline are accepted. You can't split the number over several lines. You can't use eval or equivalent.

This is code golf, so the shortest code in bytes win.

# Retina, 132 bytes

A messy, first pass solution.

(-)+\.+
5$*.$#1$*. (-|(\.))+ ?$#2
\d+
$* +(1(_)1|(_1+)|_|\+)(.*)$2$4$3
1+
$.0 \d$*x5$*- (x)+x{5}-*$#1$*-xxxx (\S{5})\S*$1
x
.


Try it online!

## Pyth, 69 63 bytes

J_.:s*R5"-.-"5jdm@Jsds*MC,mssdcMKmxJdcz)"-1"+1mtyq\+@cz)dx_1K


Try it here

Or use a test suite

Explanation

J_.:s*R5"-.-"5                                                  - Construct the morse sequence 0-10
jd                                                - Prettify output (join by spaces)
m@Jsd                                           - Get the morse for each character in output
s                                         - Convert to a string
C,mssdcMKmxJdcz)"-1"                  - Get the numbers
*M                                       - Multiply the numbers by the operators
+1mtyq\+@cz)dx_1K - Turn + and _ to +-1


Saved 6 bytes thanks to @Jakube!

• J_.:s*R5"-.-"5 for constructing the numbers. Probably even shorten when using packed strings. Commented Mar 6, 2016 at 22:56

# MATL, 757169 68 bytes

5:t!<t~v45+cXIO1Oj6ZC"@2#0)Iw!Xmfqb+wXK32=?10*}*+K?K9\6-O}V47-Y)Z{Zc


Try it online!

### General explanation

I use code format in the following so that indentation expresses the nesting of operations.

The input is split into chunks of 6 characters. The last chunk will have
5 characters padded by a 0 char.
A 0 is initially pushed. This will contain the accumulated global result.
Each operand (sequence of digits) is processed as follows. A "sign digit",
1 or -1, has been previously pushed according to whether the preceding
operator was + or - (for the first operand 1 is used as sign digit).
Then a 0 is pushed. This will contain the accumulated operand value.
Each digit of the operand is transformed into the a number 0...9 and
accumulated to the operand value, with successive multiplications by 10.
When a + or - is detected, the current operand is finished. So it is
multiplied by its sign digit, and added to the acumulated global result.
A new sign digit is pushed (1 for +, -1 for -), and a new 0 is pushed
as initial accumulated operand value for the next operand.
When a 0 char is detected instead of + or -, this marks the end of the input.
The current global accumulated result is the definitive value. This is
tranformed into Morse digits and displayed.


### Detailed explanation

5:t!<         % first half of the 10x5 array of Morse digits, with 0 for - and 1 for .
t~v           % vertically concat second half, i.e. first half vertically flipped
45+cXI        % transform 0 1 to chars - . Copy this "digit table" to clipboard I
O             % push 0: initial value for accumulated global result
1             % push 1: sign digit for first operand
O             % push 0: initial value of operand
j             % input string
6ZC           % arrange 6-length non-overlapping blocks as columns. Last is 0-padded
"             %   for each column
@           %   push column
2#0)        %   split into last element and vector or remaining elements
I           %   push digit table
w!          %   swap and transposed into a row
Xmfq        %   index of that row in the digit table. Subtract 1: gives the digit
b+          %   bubble up current operand value to top. Add to the new found digit
wXK         %   swap last char of column (+,-,space,0) to top. Copy to clipboard K
32=         %   is it space?
?           %   if so
10*       %     multiply by 10. The operand will continue with next digit
}           %   else: the operand is done
*         %     multiply by sign digit
+         %     add this operand with its sign to accumulated global result
K         %     push last char of column again
?         %     if it's not 0
K9\6-   %       push 1 if it's a +, -1 if it's a -: sign digit of next operand
O       %       push 0 to initiallize accumulated operand value of next operand
}         %     else: it's a 0: we're done computing the result
V       %       convert result to string to get its digits
47-Y)   %       index the rows of the digit table that was initially pushed
Z{Zc    %       join rows by spaces
%     end if, implicit
%   end if, implicit
% end for each, implicit
% display, implicit


# Javascript (es6) 236 bytes

plenty of room for improvement

q=>(q.replace(/[.-]{5}/g,q=>(a=q.split..length)&&q[4]=='-'?a-1:11-a).replace(/ /g,'').split(/([_+])/).reduce((l,o)=>l+(+o?(n=='_'?-(+o):+o):(n=o)&&0),0,n='')+[]).split.map(u=>(((a='.....')+'-----').slice(5-u)+a).substr(0,5)).join 


broken up

q=>
(
//grab each set of 5 dits/dahs
q.replace(/[.-]{5}/g,

//count dits
//if last digit is '-' return dits-1
//else return 11-dits
q=>(a=q.split..length)&&q[4]=='-'?a-1:11-a)

//remove spaces and split on operators + and _
.replace(/ /g,'').split(/([_+])/)

//reduce the array into one element
//when we come across a number add it to the total
//when we come across an operator change current op to it
.reduce((l,o)=>l+(+o?(n=='_'?-(+o):+o):(n=o)&&0),0,n='')

//cast to string
+[])

//turn to array
.split

//turn each digit back to morse
.map(u=>(".....-----".slice(5-u)+'.....').substr(0,5)).join 


usage

f=q=>(q.replace(/[.-]{5}/g,q=>(a=q.split..length)&&q[4]=='-'?a-1:11-a).replace(/ /g,'').split(/([_+])/).reduce((l,o)=>l+(+o?(n=='_'?-(+o):+o):(n=o)&&0),0,n='')+[]).split.map(u=>(((a='.....')+'-----').slice(5-u)+a).substr(0,5)).join 

f("----. -----+----.+..--- ----._..... .....+---..+-...._.----+----.+----._..--- -----")


### Pure bash, 366 317

a=----- p='v+=($a);a=${a/-/.}';q=${p/-?././-};. <(echo$p{,,,,} $q{,,,,});p(){ [${1:0:1} = . ]&&{ b=${1%%-*};o+=${#b};}||{ b=${1%%.*} o+=$[(5+${#b})%10];};} s=${1//[-.]/};for i in ${1//[+_]/ };do p$i;t=${s:0:1};o+=${t// };s=${s:1};done r=$[${o//_/-}];for ((i=0;i<${#r};i++));do w+=(${v[${r:i:1}]});done;echo ${w[@]}  Ok, I could save 10 bytes to reach 307 by written 1st line: v=(----- .---- ..--- ...-- ....- ..... -.... --... ---.. ----.);p(){  instead of (but I like): a=----- p='v+=($a);a=${a/-/.}';q=${p/-?././-};. <(echo $p{,,,,}$q{,,,,});p(){


Sample:

cat >/tmp/morseCalc.sh <<'eof'
#!/bin/bash
a=----- p='v+=($a);a=${a/-/.}';q=${p/-?././-};. <(echo$p{,,,,} $q{,,,,});p(){ [${1:0:1} = . ]&&{ b=${1%%-*};o+=${#b};}||{ b=${1%%.*} o+=$[(5+${#b})%10];};} s=${1//[-.]/};for i in ${1//[+_]/ };do p$i;t=${s:0:1};o+=${t// };s=${s:1};done r=$[${o//_/-}];for ((i=0;i<${#r};i++));do w+=(${v[${r:i:1}]});done;echo ${w[@]} eof chmod +x /tmp/morseCalc.sh for test in 1+1 6-3 2-3+2 2+3-4+8-5 12-6+33 90+9+29-55+8+6-1+9+9-20 ;do string="$(sed 's/ \.\.\.-\.-$//;s/ \.-\.-\. /+/g;s/ -\.\.\.\.- /_/g' <( xargs < <(morse -s --$test)))"
out="$(/tmp/morseCalc.sh "$string")"
res=$(morse -sd <<< "$out")
echo "$test:$string = $out ->$res"
done |
fold -w 80 -s

1+1: .----+.---- = ..--- -> 2
6-3: -...._...-- = ...-- -> 3
2-3+2: ..---_...--+..--- = .---- -> 1
2+3-4+8-5: ..---+...--_....-+---.._..... = ....- -> 4
12-6+33: .---- ..---_-....+...-- ...-- = ...-- ----. -> 39
90+9+29-55+8+6-1+9+9-20: ----. -----+----.+..--- ----._.....
.....+---..+-...._.----+----.+----._..--- ----- = ---.. ....- -> 84


or if morse converter is not installed:

for test in .----+.---- -...._...-- ..---_...--+..---  \
..---+...--_....-+---.._..... ".---- ..---_-....+...-- ...--" "----. -----+\
----.+..--- ----._..... .....+---..+-...._.----+----.+----._..--- -----" ;do
echo $test$(
bash <(sed '$s/;f/;echo "(${o\/\/_\/-}=$r)";f/' /tmp/morseCalc.sh ) "$test" )
done |
fold -w80 -s

.----+.---- (1+1=2) ..---
-...._...-- (6-3=3) ...--
..---_...--+..--- (2-3+2=1) .----
..---+...--_....-+---.._..... (2+3-4+8-5=4) ....-
.---- ..---_-....+...-- ...-- (12-6+33=39) ...-- ----.
----. -----+----.+..--- ----._..... .....+---..+-...._.----+----.+----._..---
----- (90+9+29-55+8+6-1+9+9-20=84) ---.. ....-
`