2010-04-21 30 views
0

在今天的工作,我们一起扔了这样的尝试:如何将8位整数转换为xquery中的二进制字符串?

xquery version "1.0"; 
declare option saxon:output    "omit-xml-declaration=yes"; 
declare variable $x := 99; 

string-join(
    for $b in (128,64,32,16,8,4,2,1) 
    let $xm := $x mod ($b*2) 
    return 
     if ($xm >= $b) then "1" else "0" 
, "") 

你有更好的办法?

以奥利弗的答案,我做了相反的功能。

declare function local:bin-byte($x as xs:string) as xs:unsignedByte 
{ 
    let $binary-nibbles := ("0000", "0001", "0010", "0011", 
          "0100", "0101", "0110", "0111", 
          "1000", "1001", "1010", "1011", 
          "1100", "1101", "1110", "1111") 
    return xs:unsignedByte(
    (index-of($binary-nibbles, substring($x,1,4))-1) * 16 
    + (index-of($binary-nibbles, substring($x,5,4))-1) 
    ) 
}; 

回答

2

作为未成年人的注意,如果你正在返回文本,而不是XML,那么你可能会更好过设置method=text而非omit-xml-declaration=yes,尽管在这种情况下,它没有什么区别。

替代的解决方案是使用查找表:如果

declare function local:binary($x as xs:unsignedByte) as xs:string 
{ 
    let $binary-nibbles := ("0000", "0001", "0010", "0011", 
          "0100", "0101", "0110", "0111", 
          "1000", "1001", "1010", "1011", 
          "1100", "1101", "1110", "1111") 
    return concat($binary-nibbles[$x idiv 16 + 1], 
       $binary-nibbles[$x mod 16 + 1]) 
}; 
+0

我们考虑过这个问题,但没有尝试。我怀疑(这对我们来说可能很重要),简单而快速。 我们的应用程序的输出将是XML或文本。在这种情况下,它可能是XML。 – philcolbourn 2010-04-22 11:55:05

+0

应该xs:byte是xs:unsignedByte? – philcolbourn 2010-04-22 12:30:22

+0

你是对的;我做了这个改变 – 2010-04-22 14:38:09

1

递归函数是明确的慢:

declare function local:decimal-to-binary ($d as xs:integer) as xs:string { 
if ($d > 0) 
then concat(local:decimal-to-binary(floor($d div 2)),$d mod 2) 
else "" 
}; 

例如

local:decimal-to-binary(42) 

与逆:

declare function local:binary-to-decimal($b as xs:string) as xs:integer { 
if ($b ne "") 
then local:binary-to-decimal(substring($b, 1, string-length($b)- 1)) * 2 
     + number(substring ($b, string-length($b),1)) 
else 0 

};

地方:二进制到十进制(本地:十进制到二进制(42))

+0

我喜欢递归。我不得不将floor()函数包装在xs:integer()中以获取saxonb(?)xquery来运行它。我还必须将数字更改为xs:integer。如果你只想要数字的最小长度二进制表示,这将是很好的。 – philcolbourn 2010-04-28 11:24:49

+0

我测试了eXist沙盒中的代码http://demo.exist-db.org/exist/sandbox/sandbox.xql - saxon必须更严格 - 可以说是xs:integer($ d div 2)。 要获得一个固定长度的字符串,请使用字符串键盘: 声明函数local:decimal-to-binary($ d as xs:integer,$ length as xs:integer){ let $ binary:= local:decimal ($ d) return concat(string-pad(“0”,$ length - string-length($ binary)),$ binary) }; local:decimal-to-binary(42,48) – 2010-04-29 06:19:56

+0

上面的函数是有效的XQuery - 函数参数转换规则应该表示参数被转换为xs:整数(因为这是参数所期望的)。我很惊讶,撒克逊人不喜欢它。 – 2010-05-05 23:26:15

1

最有效的方法我能想到做反向(至少在XQSharp)的是:

declare function local:binary-string-to-integer($binary as xs:string) 
        as xs:integer 
{ 
    local:binary-codepoints-to-integer(string-to-codepoints($binary), 1, 0) 
}; 

declare function local:binary-codepoints-to-integer(
        $codepoints as xs:integer*, 
        $current-index as xs:integer, 
        $result as xs:integer) 
        as xs:integer 
{ 
    let $current-codepoint := $codepoints[$current-index] 
    return 
    if (empty($current-codepoint)) 
    then $result 
    else local:binary-codepoints-to-integer(
      $codepoints, 
      $current-index + 1, 
      2 * $result + $current-codepoint - string-to-codepoints("0")) 
}; 

快速性能测试显示两种方法在解释查询时执行相同的操作,但在编译查询时,此方法速度提高约50%。递归函数方法还具有不限于无符号字节的优点。

无论哪种方式运行时大约10微秒,所以没什么可担心的。

相关问题