Thanks everyone for your helpful ideas! Joe
Sent from my iPhone On Nov 17, 2011, at 7:53 PM, "G. Ken Holman" <[email protected]> wrote: > At 2011-11-17 19:14 -0500, Michael Sokolov wrote: >> You might also someday be interested in the inverse function (roman numeral >> to decimal); here is what we use. It might be interesting for the group to >> compare the iterative approach here with the recursive approach to a similar >> problem in Ken's version? > > Interesting thought, Mike! > >> declare namespace ifp="http://www.ifactory.com/press"; >> >> define function ifp:roman-number-to-decimal ($roman-number as xs:string) >> { >> let $roman-tokens := <roman-tokens> >> <tok sym='M'>1000</tok> >> <tok sym='D'>500</tok> >> <tok sym='C'>100</tok> >> <tok sym='L'>50</tok> >> <tok sym='X'>10</tok> >> <tok sym='V'>5</tok> >> <tok sym='I'>1</tok> >> </roman-tokens> >> let $l := string-length($roman-number) >> return sum ( >> for $i in (0 to $l - 1) >> let $t := substring($roman-number, $l - $i, 1) >> let $s := substring($roman-number, $l - $i + 1, 1) >> let $tv := number($roman-tokens/tok[@sym=$t]) >> let $sv := number($roman-tokens/tok[@sym=$s]) >> return if ($sv and $sv gt $tv) then $tv * -1 else number($tv) >> ) >> }; > > I just modified my module as below in order to offer the inverse of Roman > numeral to decimal, using the same lookup table as I use for the initial > direction. Interestingly, the solution has very much the same shape! > > . . . . . . . . . . . . Ken > > xquery version "1.0"; > > (: > A library to transform a number less than 4000 to a sequence of Roman digits. > > Crane Softwrights Ltd. XQuery Training > :) > > module namespace n2r = "urn:X-Crane:n2roman"; > > (:the basis of transformation is a series of strings for components:) > declare variable $n2r:values as element(value)+ := > ( > <value num="1" char="I" />, > <value num="4" char="IV"/>, > <value num="5" char="V" />, > <value num="9" char="IX"/>, > <value num="10" char="X" />, > <value num="40" char="XL"/>, > <value num="50" char="L" />, > <value num="90" char="XC"/>, > <value num="100" char="C" />, > <value num="400" char="CD"/>, > <value num="500" char="D" />, > <value num="900" char="CM"/>, > <value num="1000" char="M" /> > ); > > (:return the concatenation of strings by continuous reduction:) > declare function n2r:n2roman ( $num as xs:integer ) as xs:string > { > (:as long as we have a number, keep going:) > if ( $num ) then > (:reduce by the largest number that has a string value:) > for $val in $n2r:values[@num <= $num][fn:last()] return > (:using the highest value:) > fn:concat( $val/@char,n2r:n2roman( $num - xs:integer( $val/@num ) ) ) > (:nothing left:) > else "" > }; > > (:return the sum of numbers by continuous addition:) > declare function n2r:roman2n ( $str as xs:string ) as xs:integer > { > (:as long as we have a string, keep going:) > if ( $str ) then > (:reduce by the largest number that has a string value:) > for $val in $n2r:values[starts-with($str,@char)][fn:last()] return > (:using the highest value:) > xs:integer( $val/@num ) + n2r:roman2n(substring-after($str,$val/@char)) > (:nothing left:) > else 0 > }; > > (:test all numbers up to but not including 4000:) > declare function n2r:test ( ) as xs:integer* > { > for $each in 1 to 3999 return if( $each != n2r:roman2n(n2r:n2roman($each)) ) > then $each else () > }; > > (:end of file:) > > > -- > Contact us for world-wide XML consulting and instructor-led training > Free 5-hour video lecture: XSLT/XPath 1.0 & 2.0 http://ude.my/t37DVX > Crane Softwrights Ltd. http://www.CraneSoftwrights.com/q/ > G. Ken Holman mailto:[email protected] > Google+ profile: https://plus.google.com/116832879756988317389/about > Legal business disclaimers: http://www.CraneSoftwrights.com/legal > > _______________________________________________ > [email protected] > http://x-query.com/mailman/listinfo/talk _______________________________________________ [email protected] http://x-query.com/mailman/listinfo/talk
