SHARE
TWEET

roman_numerals

amphoterrific Aug 14th, 2019 (edited) 18 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env zsh
  2. # vim:ft=zsh
  3. #convert roman numerals to arabic, or arabic to roman, depending on input
  4. #oiginally written as two separate scripts, later combined into this handy combination script
  5.  
  6. # input test {{{1
  7. if [[ ${#} -eq 1 && ( ${1} =~ '^[0-9]{1,4}$' || ${1} =~ '^[iIvVxXlLcCdDmM]+$' ) ]]; then
  8.     :
  9. else
  10.     print 'error. input failure'
  11.     exit 1
  12. fi ################################1}}}
  13.  
  14. #############################
  15. num2rom() { #{{{1
  16. typeset -A numrom #{{{2
  17. numrom=(
  18. 1       I
  19. 2       II
  20. 3       III
  21. 4       IV
  22. 5       V
  23. 6       VI
  24. 7       VII
  25. 8       VIII
  26. 9       IX
  27. 10      X
  28. 20      XX
  29. 30      XXX
  30. 40      XL
  31. 50      L
  32. 60      LX
  33. 70      LXX
  34. 80      LXXX
  35. 90      XC
  36. 100 C
  37. 200 CC
  38. 300 CCC
  39. 400 CD
  40. 500 D
  41. 600 DC
  42. 700 DCC
  43. 800 DCCC
  44. 900 CM
  45. 1000    M
  46. 2000    MM
  47. 3000    MMM
  48. ) ###################################2}}}
  49. # length of input string
  50. typeset -i LENGTH=${#1}
  51. ##########################################
  52. # this will split the input string into single character elements,
  53. # and create an associative array of these elements
  54. # with the keys being the position of the number in the input string
  55. typeset -A INPUT
  56. for X in {1..${LENGTH}}; do
  57.     INPUT[$X]=${1[$X]}
  58. done
  59. ########################################
  60. # convert the numbers to their actual value based on their position
  61. # for example, given 326, 3 becomes 300, 2 becomes 20
  62. typeset -A VALUE
  63. for X in ${(k)INPUT}; do
  64.     ZEROS=$(( ${LENGTH} - ${X} ))
  65.     case ${ZEROS} in
  66.         (0)
  67.             VALUE[$X]=${INPUT[$X]}
  68.         ;;
  69.         (1)
  70.             VALUE[$X]="${INPUT[$X]}0"
  71.         ;;
  72.         (2)
  73.             VALUE[$X]="${INPUT[$X]}00"
  74.         ;;
  75.         (3)
  76.             VALUE[$X]="${INPUT[$X]}000"
  77.         ;;
  78.     esac
  79. done
  80. ############################################
  81. # do the actual converting
  82. typeset -Ax RESULT
  83. for X in ${(k)VALUE}; do
  84.     if { grep ${VALUE[$X]} <<<${(Fk)numrom} >/dev/null 2>&1 }; then
  85.         RESULT[$X]=${numrom[${VALUE[$X]}]}
  86.     else
  87.         print 'error. input failure'
  88.         exit 1
  89.     fi
  90. done
  91. } ####################################################################################1}}}
  92. rom2num() { #{{{1
  93.  
  94. typeset -A romnum #{{{2
  95. romnum=(
  96. I   1
  97. V   5
  98. X   10
  99. L   50
  100. C   100
  101. D   500
  102. M   1000
  103. )
  104. #2}}}
  105.  
  106. # length of input string
  107. typeset -i LENGTH=${#1}
  108.  
  109. # this will split the input string into single character elements,
  110. # and create an array of these elements
  111. # for example, xix => X I X
  112. for X in {1..${LENGTH}}; do
  113.     INPUT+=( ${(U)1[$X]} )
  114. done
  115.  
  116. # this will take the array of individual input roman numeral characters
  117. # and output an array containing the arabic representation of each
  118. # for example, X I X => 10 1 10
  119. for N in ${INPUT}; do
  120.     ARAB+=( ${romnum[$N]} )
  121. done
  122.  
  123. # single or two element input {{{2
  124. case ${LENGTH} in
  125.     (1)
  126.         typeset -x RESULT=${ARAB}
  127.         return
  128.     ;;
  129.     (2)
  130.         if [[ ${ARAB[1]} -lt ${ARAB[2]} ]]; then
  131.             typeset -x RESULT=$(( ${ARAB[2]} - ${ARAB[1]} ))
  132.         else
  133.             typeset -x RESULT=$(( ${ARAB[2]} + ${ARAB[1]} ))
  134.         fi
  135.         return
  136.     ;;
  137. esac #2}}}
  138.  
  139. typeset -i INDEX=1 # this will serve as a loop counter
  140. typeset -i CURRENT
  141. typeset -i NEXT
  142. typeset -ix RESULT
  143. while [[ ${INDEX} -le ${LENGTH} ]]; do
  144.     CURRENT=${ARAB[$INDEX]}
  145.     if [[ ${INDEX} -lt ${LENGTH} ]]; then
  146.         #do this if not operating on the last element
  147.         #CURRENT=${ARAB[$INDEX]}
  148.         NEXT=${ARAB[(( $INDEX + 1 ))]}
  149.         if [[ ${NEXT} -gt ${CURRENT} ]]; then
  150.             RESULT+=$(( NEXT - CURRENT ))
  151.             INDEX+=1
  152.         else
  153.             RESULT+=${CURRENT}
  154.         fi
  155.     else
  156.         #do this for the final element
  157.         RESULT+=${CURRENT}
  158.     fi
  159.     INDEX+=1
  160. done
  161. } #####################################################1}}}
  162. #####################################
  163. # determine which function to use, plug the input into that function
  164. if [[ ${1} =~ '^[0-9]+$' ]]; then
  165.     num2rom ${1}
  166. else
  167.     rom2num ${1}
  168. fi
  169. #####################################
  170. # print the output
  171. if [[ ${(t)RESULT} == association* ]]; then
  172.     for X in ${(ki)RESULT}; do
  173.         print -n ${RESULT[$X]}
  174.     done; print ''
  175. else
  176.     print ${RESULT}
  177. fi
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top