用于对字符串中的字符进行计数/格式化的xquery递归

用于对字符串中的字符进行计数/格式化的xquery递归,xquery,Xquery,我试图在xquery 1.0中找到以下问题的解决方案。我只需要单独使用递归函数。输入的字符始终仅在A-Z之间 1. AAABBCCD --> A1A2A3-B1B2-C1C2-D1 2. ABBAB --> A1-B1B2-A2-B3 谢谢。到目前为止,我所做的尝试没有任何结果。首先,您可能希望将字符串拆分为单个字符,这可以通过多种方式完成(例如,使用fn:substring(…)),我将使用fn:string-to-codepoints($str): 示例:local:t

我试图在xquery 1.0中找到以下问题的解决方案。我只需要单独使用递归函数。输入的字符始终仅在A-Z之间

1. AAABBCCD --> A1A2A3-B1B2-C1C2-D1
2. ABBAB     --> A1-B1B2-A2-B3

谢谢。到目前为止,我所做的尝试没有任何结果。

首先,您可能希望将字符串拆分为单个字符,这可以通过多种方式完成(例如,使用
fn:substring(…)
),我将使用
fn:string-to-codepoints($str)

示例:
local:to chars('ABC')
生成序列
('A','B','C')

对于格式化方案,您必须跟踪

  • 在编号点之前遇到每个字符的频率,以及
  • 前一个字符是什么(对于破折号)
  • 我将跟踪XQuery 3.0中每个字符的计数,并将前一个字符保留在递归函数的单独参数中。现在要做的就是

    • 一个接一个地检查每个字符
    • 获取并更新其在地图中的计数
    • 决定是否在输出字符串中的破折号之前添加破折号
    • 然后再发生
    处理完所有字符后,我们就完成了

    declare function local:format($chars, $counts, $last, $out) {
      if(empty($chars)) then $out
      else (
        let $c          := head($chars),              (: current char :)
            $new-chars  := tail($chars),              (: rest of the chars :)
            $count      := ($counts($c), 1)[1],       (: old count if present, `1` otherwise :)
            $cc         := $c || $count,              (: char with count :)
            $new-out    := if($c eq $last) then $out || $cc  (: updated output string :)
                           else $out || '-' || $cc,
            $new-counts := map:put($counts, $c, $count + 1)  (: updated map :)
        return local:format($new-chars, $new-counts, $c, $new-out)
      )
    };
    
    我们使用空映射调用它,并将序列中的第一个字符称为“previous”字符,以避免在输出的开头出现破折号

    declare function local:format-string($str) {
      let $chars := local:to-chars($str)
      return local:format($chars, map{}, head($chars), '')
    };
    
    这适用于任意字符:
    local:format string('HELLO')
    产生
    'H1-E1-L1L2-O1'

    编辑:

    我一定跳过了XQuery1.0部分,我指责咖啡因的缺乏。。。您还可以将计数保留为26个整数的序列,而不是映射:

    declare function local:format($chars, $counts, $last, $out) {
      if(empty($chars)) then $out
      else (
        let $c          := $chars[1],
            $new-chars  := subsequence($chars, 2),
            $pos        := string-to-codepoints($c) - 64,
            $count      := $counts[$pos],
            $cc         := $c || $count,
            $new-out    := if($c eq $last) then concat($out, $cc)
                           else concat($out, '-', $cc),
            $new-counts :=
              (
                subsequence($counts, 1, $pos - 1),
                $count + 1,
                subsequence($counts, $pos + 1)
              )
        return local:format($new-chars, $new-counts, $c, $new-out)
      )
    };
    
    declare function local:format-string($str) {
      let $chars := local:to-chars($str),
          $counts := for $i in 1 to 26 return 1
      return local:format($chars, $counts, head($chars), '')
    };
    
    我试图了解如何在XQuery1.0中实现以下功能。我是 仅使用递归函数寻找解决方案。这个 输入将始终只有A-Z之间的字符

    1. AAABBCCD --> A1A2A3-B1B2-C1C2-D1
    2. ABBAB     --> A1-B1B2-A2-B3
    
    这里有一个XPath 2.0表达式

     string-join(
                 (for $s in .,
                   $indS in 1 to string-length($s),
                   $cp in string-to-codepoints($s)[$indS]
                    return
                      (
                      '-'[$indS gt 1 and $cp ne string-to-codepoints($s)[$indS -1]]
                        ,
                        concat(codepoints-to-string($cp),
                                for $i in 1 to count(index-of(string-to-codepoints($s), $cp))
                                 return
                                   $i[index-of(string-to-codepoints($s), $cp)[$i] eq $indS]
                               )
                        )
                    ),
                  ''
                 )
    
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
      <xsl:template match="t">
        <xsl:sequence select=
         "string-join(
                     (for $s in .,
                       $indS in 1 to string-length($s),
                       $cp in string-to-codepoints($s)[$indS]
                        return
                          (
                          '-'[$indS gt 1 and $cp ne string-to-codepoints($s)[$indS -1]]
                            ,
                            concat(codepoints-to-string($cp),
                                    for $i in 1 to count(index-of(string-to-codepoints($s), $cp))
                                     return
                                       $i[index-of(string-to-codepoints($s), $cp)[$i] eq $indS]
                                   )
                            )
                        ),
                      ''
                     )
           "/>
      </xsl:template>
    </xsl:stylesheet>
    
    <z>
        <t>AAABBCCD</t>
        <t>ABBAB</t>
        <t>aBcBaBcc</t>
    </z>
    
    A1A2A3-B1B2-C1C2-D1
    A1-B1B2-A2-B3
    a1-B1-c1-B2-a2-B3-c2c3
    
    这当然是非递归的,我认为这是一个优势——我们保证不会发生调用堆栈溢出:)


    ->>>>>还要注意,输入字符可以有任何值,而不仅仅是[A-Z]。使用简单的序列将XQuery 3.0、基于地图的解决方案很好地转换为某种XQuery 1.0方式。但是我认为,XQuery1中没有
    head
    tail
    ,因此需要添加更多的
    子序列
    或谓词。使用
    concat
    而不是
    | |
    。Leo和@MartinHonnen,只是为了记录,存在一个XPath 2.0表达式/解决方案-当然是非递归的,因为这是XPath 2.0 Hanks Martin,我希望现在是正确的XQ1.0。感谢您的回复。我的任务是学习xquery中的递归,并了解如何在递归调用之间管理变量。你的帖子向我展示了在xquery中解决问题的那些部分。我没有为头/尾/管的小问题烦恼。@LeoWörteler,这是否只适用于拉丁字母表中的26个字符?也许一个更普遍的解决方案对读者更有用?好问题。作为记录,存在一个XPath2.0解决方案——当然是非递归的,因为这是XPath2.0。当然,这也是一个XQuery 1.0解决方案,因为XQuery 1.0是Xpath 2.0Slkrasnodar的超集,我的答案对解决您的问题有用吗?如果您对此有任何疑问/问题,请在评论中说明。如果一切都好的话,请考虑接受一个回答。@ DimitreNovatchev,谢谢你的回答。我仍在阅读Leo的第一个答案,并将其移植到OracleEnv。仅供参考,我对两个答案都投了赞成票。请给我一些时间,如果我有问题,我可以回来。斯克拉斯诺达尔,没问题。新年快乐学到了一些东西。正如你所说,你的答案可能更有效,但我可能已经用我的标题和问题的措辞影响了利奥,让他在回复中发表自己的观点。因此,我选择了这一点作为我接受的答案。谢谢。@Slkrasnodar,很高兴这个回答有帮助。无论您接受哪种答案,我都强烈建议在实际生产工作中使用非递归解决方案,以避免意外的崩溃。至少在BaseX中,这两个问题(调用堆栈和每个递归调用的新序列)实际上并不相关。由于函数是尾部递归的,因此调用堆栈不会任意增长。这是大多数XQuery处理器都应该实现的众所周知的优化。序列在内部表示为Finger Trees(B树的变体),这意味着在中间插入值会导致与原始结构共享大部分结构的序列。函数式语言的良好实现不应阻碍递归算法。很好的评论,@LeoWörteler,是的,并非所有的XQuery处理器都是平等的。感谢您在BaseX中实现手指树数据结构!我看到一位权威人士的声明,W3C工作组没有强制要求尾部递归优化,因为他们不知道如何严格定义“尾部递归”。。。