arab numerals - roman numerals
Posted: 2010-06-12 03:04:40
Has there ever been a macro to output roman numerals from arab ones and vice versa? Or maybe this is not as simple as that?
Code: Select all
### Arabic Numeral to Roman Numeral ###
# Convert Arabic numeral(s) in selection(s) to Roman numeral(s).
# Only numerals from 1 to 3999 are supported.
Require Application Version '3.2'
$doc = Document.active
$thousands = ','
$comma = System Property 'use comma for decimal point'
if $comma == true
$thousands = '.'
end
$findArabicNumerals = '[0-9]+(?:[0-9' & $thousands # construct a find expression for Arabic numerals
$findArabicNumerals &= '])*'
$numfound = Find All $findArabicNumerals, 'Es' # E: PowerFind Pro; s: in selections
if ! $numfound
Exit 'No Arabic numeral found in selection(s), exit...'
end
$selections = $doc.textSelections
$romanIXCM = Array.new ('I', 'X', 'C', 'M') # create an array
$romanVLD = Array.new ('V', 'L', 'D') # create another array
$errorMessage = ''
foreach $sel in reversed $selections
$validArabicNumeral = true
$roman = ''
$arabic = $sel.subtext
$arabic.replaceAll $thousands, ''
if $arabic > 3999
$validArabicNumeral = false
$errorMessage &= 'Cannot convert ' & $sel.subtext
$errorMessage &= " which is greater than 3999.\n"
end
if $arabic < 1
$validArabicNumeral = false
$errorMessage &= 'Cannot convert ' & $sel.subtext
$errorMessage &= " which is less than 1.\n"
end
if $validArabicNumeral == true
$arabic = $arabic.split ''
$i = 0
$j = $arabic.count - 1
while $i < $j # reverse values in $arabic
$arabic.swapValuesAtIndexes $i, $j
$i += 1
$j -= 1
end
$limit = $arabic.count
$i = 0
while $i < $limit
if $arabic[$i] == 4
# When $i is 0, $romanIXCM[0] is "I" and $romanVLD[0] is "V".
$roman = $romanVLD[$i] & $roman
$roman = $romanIXCM[$i] & $roman
elsif $arabic[$i] == 9
$roman = $romanIXCM[$i+1] & $roman
$roman = $romanIXCM[$i] & $roman
elsif $arabic[$i] < 4
# When $i is 2, $romanIXCM[2] is "C" and $romanIXCM[2+1] is "M".
# When $i is 3, $romanIXCM[3] is "M" and $arabic[3] is "1".
$c = $arabic[$i]
while $c > 0
$roman = $romanIXCM[$i] & $roman
$c -= 1
end
else # if $arabic[$i] is 6 or 7 or 8
# When $i is 1, $romanVLD[1] is "L", $romanIXCM[1] is "X"
# and $arabic[1] is "8". So ($arabic[1] - 5) = 3.
$c = $arabic[$i] - 5
while $c > 0
$roman = $romanIXCM[$i] & $roman
$c -= 1
end
$roman = $romanVLD[$i] & $roman
end
$i += 1
end
$roman = Cast to String $roman
$sel.text.replaceInRange $sel.range, $roman
end
end
if $errorMessage
Exit $errorMessage
end
Code: Select all
### Roman Numeral to Arabic Numeral ###
# Convert Roman numeral(s) in selection(s) to Arabic numeral(s).
# Only numbers from 1 to 3999 are supported.
Require Application Version '3.1'
$doc = Document.active
$selections = $doc.textSelections
$errorMessage = ''
if ! $selections.firstValue.length
Exit 'Nothing selected, exit...'
end
$errorMessage = ''
$roman2arabic = Hash.new
$roman2arabic{'I'} = '1'
$roman2arabic{'V'} = '5'
$roman2arabic{'X'} = '10'
$roman2arabic{'L'} = '50'
$roman2arabic{'C'} = '100'
$roman2arabic{'D'} = '500'
$roman2arabic{'M'} = '1000'
foreach $sel in reversed $selections
$roman = $sel.subtext
$roman.replaceAll '\x20|\xA0', '', 'E'
# Transformm, for example, "M CM XL III" to "MCMXLIII"
# \x20 space
# \xA0 no-break space
# | OR operator
$matched = $roman.find '(?x) # See if it is a valid roman numeral
^(
(?: M{1,3} )?
(?: D?C{1,3} | C?[DM] )?
(?: L?X{1,3} | X?[LC] )?
(?: V?I{1,3} | I?[VX] )?
)$', 'Ei' # (?x) eXtended mode (ignore white space)
# ^ strings start
# ( ) group (captured)
# (?: ) group (not captured)
# ? zero or one time
# {1,3} match at least 1 but not more than 3 times
# | OR operator
if ! $matched.length # if $matched is empty, then it is an invalid roman numeral
$errorMessage &= "\"$roman\" is not a valid Roman numeral.\n"
else
$roman.replaceAll '(?=I[VX])|(?=X[LC])|(?=C[DM])', '-', 'Ei'
# insert "-" before
# "I" preceding "V" or "X",
# "X" preceding "L" or "C" and
# "C" preceding "D" or "M"
# because they are negative
# to transform "MCMXLIII" into "M-CM-XLIII"
$roman.replaceAll '(?<!-)(?!-)(?=\S)', '+', 'E'
# insert "+" before non-minus character
# and non-minus character
# to transform "M-CM-XLIII" into "+M-C+M-X+L+I+I+I"
$range = Range.new 0, $roman.length
$roman.transliterateInRange $range, $roman2arabic # replace "I" with "1"
$i = 0
$plus = $minus = Array.new
$plusSels = $roman.findAll '(?<=\+)[^+-]+', 'E'
foreach $n in $plusSels
$plus.appendValue $n.subtext
end
foreach $n in $plus
$i += $n
end
$minusSels = $roman.findAll '(?<=-)[^+-]+', 'E'
foreach $n in $minusSels
$minus.appendValue $n.subtext
end
foreach $n in $minus
$i -= $n
end
$sel.text.replaceInRange $sel.range, $i
end
end
if $errorMessage # if $errorMessage is not empty
Exit $errorMessage # show $errorMessage
end
That is no-break spaces inserted by php. Runjs wrote:The macro does not execute and complains about the length property "requiring an object under $matched".
Code: Select all
Replace All '\xA0', '\x20', 'E'
Duplicate the macro and just make lowercase the definitions of $romanIXCM and $romanVLD, i.e.js wrote:for Arabic -> Roman
Code: Select all
$romanIXCM = Array.new ('i', 'x', 'c', 'm')
$romanVLD = Array.new ('v', 'l', 'd')
Code: Select all
$Case = prompt options "Do you want roman numerals to be uppercase or lowercase?", "", "OK", "UPPERCASE", "lowercase"
if $Case == "UPPERCASE"
$romanIXCM = Array.new ('I', 'X', 'C', 'M') # create an array
$romanVLD = Array.new ('V', 'L', 'D') # create another array
elsif $Case == "lowercase"
$romanIXCM = Array.new ('i', 'x', 'c', 'm') # create an array
$romanVLD = Array.new ('v', 'l', 'd') # create another array
end
Code: Select all
$romanIXCM = Array.new ('I', 'X', 'C', 'M') # create an array
$romanVLD = Array.new ('V', 'L', 'D') # create another array
Code: Select all
### Arabic Numeral to Roman Numeral ###
# Convert Arabic numeral(s) in selection(s) to Roman numeral(s).
# Only numerals from 1 to 3999 are supported.
Require Application Version '3.2'
$doc = Document.active
$thousands = ','
$comma = System Property 'use comma for decimal point'
if $comma == true
$thousands = '.'
end
$findArabicNumerals = '[0-9]+(?:[0-9' & $thousands # construct a find expression for Arabic numerals
$findArabicNumerals &= '])*'
$numfound = Find All $findArabicNumerals, 'Es' # E: PowerFind Pro; s: in selections
if ! $numfound
Exit 'No Arabic numeral found in selection(s), exit...'
end
$selections = $doc.textSelections
$errorMessage = ''
foreach $sel in reversed $selections
$validArabicNumeral = true
$roman = ''
$arabic = $sel.subtext
$arabic.replaceAll $thousands, ''
if $arabic > 3999
$validArabicNumeral = false
$errorMessage &= 'Cannot convert ' & $sel.subtext
$errorMessage &= " which is greater than 3999.\n"
end
if $arabic < 1
$validArabicNumeral = false
$errorMessage &= 'Cannot convert ' & $sel.subtext
$errorMessage &= " which is less than 1.\n"
end
if $validArabicNumeral
while $arabic > 999
$arabic -= 1000
$roman &= ‘M’
end
if $arabic > 499
$arabic -= 500
$roman &= ‘D’
end
while $arabic > 99
$arabic -= 100
$roman &= ‘C’
end
if $arabic > 49
$arabic -= 50
$roman &= ‘L’
end
while $arabic > 9
$arabic -= 10
$roman &= ‘X’
end
if $arabic > 4
$arabic -= 5
$roman &= ‘V’
end
while $arabic > 0
$arabic -= 1
$roman &= ‘I’
end
$roman.findAndReplace ‘DCCCC’, ‘CM’
$roman.findAndReplace ‘CCCC’, ‘CD’
$roman.findAndReplace ‘LXXXX’, ‘XC’
$roman.findAndReplace ‘XXXX’, ‘XL’
$roman.findAndReplace ‘VIIII’, ‘IX’
$roman.findAndReplace ‘IIII’, ‘IV’
$sel.text.replaceInRange $sel.range, $roman
end
end
if $errorMessage
Exit $errorMessage
end
haha, yes, Roman numerals are a pain to work with. I don't know anything about the history behind them, but they seem quite impractical as compared to Arabic numbers.phspaelti wrote:So Roman numerals are much too stupid a technology for him
Code: Select all
### Arabic Numeral to Roman Numeral ###
# Convert Arabic numeral(s) in selection(s) to Roman numeral(s).
# Only numerals from 1 to 3999 are supported.
Require Application Version '3.2'
$doc = Document.active
$thousands = ','
$comma = System Property 'use comma for decimal point'
if $comma == true
$thousands = '.'
end
$findArabicNumerals = '[0-9]+(?:[0-9' & $thousands # construct a find expression for Arabic numerals
$findArabicNumerals &= '])*'
$numfound = Find All $findArabicNumerals, 'Es' # E: PowerFind Pro; s: in selections
if ! $numfound
Exit 'No Arabic numeral found in selection(s), exit...'
end
$selections = $doc.textSelections
$errorMessage = ''
$romanNumerals = Hash.new 1,‘I’, 5,‘V’, 10,‘X’, 50,‘L’, 100,‘C’, 500,‘D’, 1000,‘M’
$romanDigitValues = $romanNumerals.keys
$romanDigitValues.sort
foreach $sel in reversed $selections
$validArabicNumeral = true
$roman = ''
$arabic = $sel.subtext
$arabic.replaceAll $thousands, ''
if $arabic > 3999
$validArabicNumeral = false
$errorMessage &= 'Cannot convert ' & $sel.subtext
$errorMessage &= " which is greater than 3999.\n"
end
if $arabic < 1
$validArabicNumeral = false
$errorMessage &= 'Cannot convert ' & $sel.subtext
$errorMessage &= " which is less than 1.\n"
end
if $validArabicNumeral
foreach $romanDigitValue in reversed $romanDigitValues
while $arabic >= $romanDigitValue
$arabic -= $romanDigitValue
$roman &= $romanNumerals{$romanDigitValue}
end
end
$roman.findAndReplace ‘DCCCC’, ‘CM’
$roman.findAndReplace ‘CCCC’, ‘CD’
$roman.findAndReplace ‘LXXXX’, ‘XC’
$roman.findAndReplace ‘XXXX’, ‘XL’
$roman.findAndReplace ‘VIIII’, ‘IX’
$roman.findAndReplace ‘IIII’, ‘IV’
$sel.text.replaceInRange $sel.range, $roman
end
end
if $errorMessage
Exit $errorMessage
end
Code: Select all
### Roman Numeral to Arabic Numeral ###
# Convert Roman numeral(s) in selection(s) to Arabic numeral(s).
# Only numbers from 1 to 3999 are supported.
Require Application Version '3.1'
$doc = Document.active
$selections = $doc.textSelections
$errorMessage = ''
if ! $selections.firstValue.length
Exit 'Nothing selected, exit...'
end
$errorMessage = ''
$romanNumerals = Hash.new ‘I’,1, ‘V’,5, ‘X’,10, ‘L’,50, ‘C’,100, ‘D’,500, ‘M’,1000
foreach $sel in reversed $selections
$roman = $sel.subtext
$roman.replaceAll '\x20|\xA0', '', 'E'
# Transform, for example, "M CM XL III" to "MCMXLIII"
# \x20 space
# \xA0 no-break space
# | OR operator
$isRoman = $roman.find '(?x)^(
(?: M*)?
(?: D?C{1,4} | C?[DM])?
(?: L?X{1,4} | X?[LC])?
(?: V?I{1,4} | I?[VX])?
)$', 'Ei' # ^ strings start
# ( ) group (captured)
# (?: ) group (not captured)
# ? zero or one time
# {1,3} match at least 1 but not more than 3 times
# | OR operator
if ! $isRoman
$errorMessage &= "\"$roman\" is not a valid Roman numeral.\n"
else
$romanLetters = $roman.split ‘’
$arabic = 0
$lastLetterValue = 0
foreach $letter in $romanLetters
$letterValue = $romanNumerals{$letter}
if $lastLetterValue < $letterValue
$arabic -= $lastLetterValue
else
$arabic += $lastLetterValue
end
$lastLetterValue = $letterValue
end
$arabic += $lastLetterValue
$sel.text.replaceInRange $sel.range, $arabic
end
end
if $errorMessage # if $errorMessage is not empty
Exit $errorMessage # show $errorMessage
end