2

多くの言語では、正規表現キャプチャ グループを 1 つ以上の変数に割り当てることができます。これは XQuery にも当てはまりますか? これまでに得た最善の方法は、「キャプチャ グループによる置換」を行うことですが、それは最も美しいオプションではないようです。

これは私たちが今持っているものです:

let $text := fn:replace($id, '(.+)(\d+)', '$1');
let $snr := fn:replace($id, '(.+)(\d+)', '$2');

動作します。しかし、私は次のようなものがあることを望んでいたでしょう:

let ($text, $snr) := fn:matches($id, '(.+)(\d+)');

それ(または同様のもの)は存在しますか?

4

2 に答える 2

3

Plain XQuery 1.0 は一致グループを返すことをサポートしていません。この欠点はを提供する XQuery 関数ライブラリでfunctx:get-matches解決されていますが、実装は効率的とは言えません。

XQuery 3.0 は、非常に強力な機能を知っていますfn:analyze-string。この関数は、一致する部分と一致しない部分の両方を返します。正規表現で定義されている場合は、一致グループによって分割されます。

上にリンクされている 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 エンジンのドキュメントをお読みください。

于 2016-10-24T10:24:38.840 に答える
0

特定の文字がキャプチャ グループ内に存在しないことがわかっている場合は、グループ間でその文字に置き換えてから、XQuery 1 でトークン化できます。

例えば:

tokenize(replace("abc1234", "(.+)(\d+)", "$1-$2"), "-")

置換によってグループの前後のすべてが削除されるようにするには:

tokenize(replace("abc1234", "^.*?(.+?)(\d+).*?$", "$1-$2"), "-")

string-join を使用して、任意のセパレータに対して "$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+)")
于 2016-10-24T13:18:06.603 に答える