将捕获组分配给 XQuery 中的变量
Assign capture groups to variables in XQuery
在许多语言中,可以将正则表达式捕获组分配给一个或多个变量。在 XQuery 中也是如此吗?到目前为止我们得到的最好结果是 'replace by capture group',但这似乎不是最好的选择。
这就是我们现在拥有的:
let $text := fn:replace($id, '(.+)(\d+)', '');
let $snr := fn:replace($id, '(.+)(\d+)', '');
有效。但我希望有这样的东西:
let ($text, $snr) := fn:matches($id, '(.+)(\d+)');
那个(或类似的东西)存在吗?
Plain XQuery 1.0 不支持返回匹配组。这个缺点在XQuery function library which provides functx:get-matches
中已经解决了,但是实现起来还算不上高效。
XQuery 3.0 知道非常强大的功能fn:analyze-string
。函数 returns 匹配和非匹配部分,如果在正则表达式中定义了匹配组,也会按匹配组拆分。
上面链接的 Marklogic 文档中的示例,但该函数来自标准 XPath/XQuery 3.0 函数库,也可用于其他 XQuery 3.0 实现:
fn:analyze-string('Tom Jim John',"((Jim) John)")
=>
<s:analyze-string-result>
<s:non-match>Tom </s:non-match>
<s:match>
<s:group nr="1">
<s:group nr="2">Jim</s:group>
John
</s:group>
</s:match>
</s:analyze-string-result>
如果您不支持 XQuery 3.0:某些引擎提供类似的实现定义函数或允许使用 Java 代码之类的后端函数,请在这种情况下阅读 XQuery 引擎的文档。
如果您知道某个字符不会出现在捕获组中,您可以在组之间使用该字符替换,然后在 XQuery 1 中对其进行标记化。
例如:
tokenize(replace("abc1234", "(.+)(\d+)", "-"), "-")
为确保替换删除所有内容 before/after 群组:
tokenize(replace("abc1234", "^.*?(.+?)(\d+).*?$", "-"), "-")
您可以通过使用字符串连接为任何分隔符创建替换模式(如“$1-$2-$3-$4”)将其泛化为函数:
declare function local:get-matches($input, $regex, $separator, $groupcount) {
tokenize(replace($input, concat("^.*?", $regex, ".*?$"), string-join(for $i in 1 to $groupcount return concat("$", $i), $separator)), $separator, "q" )
};
local:get-matches("abc1234", "(.+?)(\d+)", "|", 2)
如果你不想自己指定分隔符,你需要一个函数来找到一个。每个比输入字符串长的字符串都不能出现在捕获组中,因此您总是可以使用更长的分隔符找到一个:
declare function local:get-matches($input, $regex, $separator) {
if (contains($input, $separator)) then local:get-matches($input, $regex, concat($separator, $separator))
else
let $groupcount := count(string-to-codepoints($regex)[. = 40])
return tokenize(replace($input, concat("^.*?", $regex, ".*?$"), string-join(for $i in 1 to $groupcount return concat("$", $i), $separator)), $separator, "q" )
};
declare function local:get-matches($input, $regex) {
local:get-matches($input, $regex, "|#☎")
};
local:get-matches("abc1234", "(.+?)(\d+)")
在许多语言中,可以将正则表达式捕获组分配给一个或多个变量。在 XQuery 中也是如此吗?到目前为止我们得到的最好结果是 'replace by capture group',但这似乎不是最好的选择。
这就是我们现在拥有的:
let $text := fn:replace($id, '(.+)(\d+)', '');
let $snr := fn:replace($id, '(.+)(\d+)', '');
有效。但我希望有这样的东西:
let ($text, $snr) := fn:matches($id, '(.+)(\d+)');
那个(或类似的东西)存在吗?
Plain XQuery 1.0 不支持返回匹配组。这个缺点在XQuery function library which provides functx:get-matches
中已经解决了,但是实现起来还算不上高效。
XQuery 3.0 知道非常强大的功能fn:analyze-string
。函数 returns 匹配和非匹配部分,如果在正则表达式中定义了匹配组,也会按匹配组拆分。
上面链接的 Marklogic 文档中的示例,但该函数来自标准 XPath/XQuery 3.0 函数库,也可用于其他 XQuery 3.0 实现:
fn:analyze-string('Tom Jim John',"((Jim) John)")
=>
<s:analyze-string-result>
<s:non-match>Tom </s:non-match>
<s:match>
<s:group nr="1">
<s:group nr="2">Jim</s:group>
John
</s:group>
</s:match>
</s:analyze-string-result>
如果您不支持 XQuery 3.0:某些引擎提供类似的实现定义函数或允许使用 Java 代码之类的后端函数,请在这种情况下阅读 XQuery 引擎的文档。
如果您知道某个字符不会出现在捕获组中,您可以在组之间使用该字符替换,然后在 XQuery 1 中对其进行标记化。
例如:
tokenize(replace("abc1234", "(.+)(\d+)", "-"), "-")
为确保替换删除所有内容 before/after 群组:
tokenize(replace("abc1234", "^.*?(.+?)(\d+).*?$", "-"), "-")
您可以通过使用字符串连接为任何分隔符创建替换模式(如“$1-$2-$3-$4”)将其泛化为函数:
declare function local:get-matches($input, $regex, $separator, $groupcount) {
tokenize(replace($input, concat("^.*?", $regex, ".*?$"), string-join(for $i in 1 to $groupcount return concat("$", $i), $separator)), $separator, "q" )
};
local:get-matches("abc1234", "(.+?)(\d+)", "|", 2)
如果你不想自己指定分隔符,你需要一个函数来找到一个。每个比输入字符串长的字符串都不能出现在捕获组中,因此您总是可以使用更长的分隔符找到一个:
declare function local:get-matches($input, $regex, $separator) {
if (contains($input, $separator)) then local:get-matches($input, $regex, concat($separator, $separator))
else
let $groupcount := count(string-to-codepoints($regex)[. = 40])
return tokenize(replace($input, concat("^.*?", $regex, ".*?$"), string-join(for $i in 1 to $groupcount return concat("$", $i), $separator)), $separator, "q" )
};
declare function local:get-matches($input, $regex) {
local:get-matches($input, $regex, "|#☎")
};
local:get-matches("abc1234", "(.+?)(\d+)")