代码之家  ›  专栏  ›  技术社区  ›  tsul

使用jq将数字字节值数组转换为字符串

  •  3
  • tsul  · 技术社区  · 7 年前

    我将一个UTF-8字符串的二进制表示为一个数值数组,每个数值的范围为0。。255

    如何使用将该数组转换为字符串 jq ? 内置的 implode 仅处理码点阵列。此外,中没有用于按位操作的函数 jq公司 .


    这些数组在newman(Postman CLI)json输出属性中作为值进行观察 response.stream.data .

    例如,字符串“Hi,!”进入 [72,105,44,32,208,156,208,184,209,128,33] 字节数组,而其代码点为 [72,105,44,32,1052,1080,1088,33] . 向心聚爆 后者给出了原始字符串,而 向心聚爆 前者给出“Hi,ÐиÃ!”或者类似的东西。

    4 回复  |  直到 7 年前
        1
  •  3
  •   peak    7 年前
    def btostring:
      if length == 0 then ""
    
      elif .[0] >= 240 then
         ([((((.[0] - 240) * 64) + (.[1] - 128)) * 64 + (.[2] - 128)) * 64 + (.[3] - 128)]
          | implode) + (.[4:] | btostring)
    
      elif .[0] >= 224 then
         ([  ((.[0] - 224) * 64 +  (.[1] - 128)) * 64 + (.[2] - 128)]
          | implode) + (.[3:] | btostring)
    
      elif .[0] >= 128 then
         ([  (.[0] - 192)  * 64 +  (.[1] - 128) ]
          | implode) + (.[2:] | btostring)
    
      else  (.[0:1] | implode ) + (.[1:] | btostring)
      end;
    

    例子:

    def hi: [72,105,44,32,208,156,208,184,209,128,33] ;
    
    hi | btostring
    

    输出(使用 jq -r ):

    Hi, Мир!
    

    扩展示例:

    def hi: [72,105,44,32,208,156,208,184,209,128,33];
    def euro: [226,130,172];        # 11100010 10000010 10101100
    def fire: [240,159,156,130];    # 11110000 10011111 10011100 10000010
    
    (hi, euro, fire) | btostring
    

    输出:

    Hi, Мир!
    €
    🜂
    

    (在某些设备上,上面的最后一行是长方体而不是三角形。)

        2
  •  3
  •   ygoe    4 年前

    这是递归的非递归版本 btostring 在本页的其他地方给出,主要是为了说明如何在jq中将递归实现转化为非递归实现。

    def btostring:
      . as $in
      | [ foreach range(0;length) as $ix ({skip:0, point:[]};
            if .skip > 0 then .skip += -1
            elif $in[$ix] >= 240 then
              .point = [(((($in[$ix]   - 240)  * 64)
                         + ($in[$ix+1] - 128)) * 64
                         + ($in[$ix+2] - 128)) * 64
                         + ($in[$ix+3] - 128)]
              | .skip = 3
            elif $in[$ix] >= 224 then
              .point = [  (($in[$ix]   - 224)  * 64
                         + ($in[$ix+1] - 128)) * 64
                         + ($in[$ix+2] - 128)]
              | .skip = 2
            elif $in[$ix] >= 128 then
              .point = [   ($in[$ix]   - 192)  * 64
                         + ($in[$ix+1] - 128)]
              | .skip = 1
            else .point = $in[$ix:$ix+1]
            end;
            if .skip == 0 then .point|implode else empty end) ]
      | add ;
    
        3
  •  2
  •   tsul    7 年前

    另一种方法是使用 foreach . 其主要思想是保持剩余的读取字节数( .[0] )对于当前字符和到目前为止读取的位( .[1] ). 以下是过滤器:

    [foreach .[] as $item (
        [0, 0]
        ;
        if .[0] > 0 then [.[0] - 1, .[1] * 64 + ($item % 64)]
        elif $item >= 240 then [3, $item % 8]
        elif $item >= 224 then [2, $item % 16]
        elif $item >= 192 then [1, $item % 32]
        elif $item < 128 then [0, $item]
        else error("Malformed UTF-8 bytes")
        end
        ;
        if .[0] == 0 then .[1] else empty end
    )] | implode
    

    此外,错误字节的错误检测也没有完成。

        4
  •  0
  •   ygoe    4 年前

    基于 answer of peak 我成功地使用了一个扩展,它不会因无效而中断或失败 UTF-8 encoding .

    无效的UTF-8起始字节(128-193、245-255)或序列被解释为ISO 8859-1。

    def btostring:
        if type != "array" then .
        elif length == 0 then ""
        elif .[0] >= 245 then
            (.[0:1] | implode ) + (.[1:] | btostring)
        elif .[0] >= 240 then
            if length >= 4 and .[1] >= 128 and .[2] >= 128 and .[3] >= 128 then
                ([((((.[0] - 240) * 64) + (.[1] - 128)) * 64 + (.[2] - 128)) * 64 + (.[3] - 128)] | implode) + (.[4:] | btostring)
            else
                (.[0:1] | implode ) + (.[1:] | btostring)
            end
        elif .[0] >= 224 then
            if length >= 3 and .[1] >= 128 and .[2] >= 128 then
                ([  ((.[0] - 224) * 64  + (.[1] - 128)) * 64 + (.[2] - 128)] | implode) + (.[3:] | btostring)
            else
                (.[0:1] | implode ) + (.[1:] | btostring)
            end
        elif .[0] >= 194 then
            if length >= 2 and .[1] >= 128 then
                ([   (.[0] - 192) * 64  + (.[1] - 128) ] | implode) + (.[2:] | btostring)
            else
                (.[0:1] | implode ) + (.[1:] | btostring)
            end
        else
            (.[0:1] | implode ) + (.[1:] | btostring)
        end;