2016-10-24 13 views
2

많은 언어에서 하나 이상의 변수에 정규식 캡처 그룹을 할당 할 수 있습니다. XQuery에서도 마찬가지입니까? 우리가 지금까지 얻은 최선은 '캡쳐 그룹으로 대체'를하고 있지만, 그것은 가장 좋은 옵션으로 보이지 않습니다. 작동XQuery에서 변수에 캡처 그룹 할당

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

을 :

이것은 우리가 지금 가지고있는 것입니다. 그러나 나는 다음과 같은 것을 기대했을 것입니다 :

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

그 비슷한 것입니까?

답변

2

일반 XQuery 1.0에는 일치하는 그룹을 반환하는 기능이 없습니다. 이 단점은 XQuery function library which provides functx:get-matches에서 해결되었지만 구현은 효율적인 것으로 간주되지 않습니다.

XQuery 3.0은 매우 강력한 함수 fn:analyze-string을 알고 있습니다. 이 함수는 일치하는 부분과 일치하지 않는 부분을 모두 반환하고, 일치하는 그룹이 정규 표현식에 정의되어 있으면 분할합니다.

위의 링크 Marklogic 문서에서 예,하지만 기능은 표준의 XPath/XQuery를 3.0 함수 라이브러리에서 다른 XQuery를 3.0 구현도 제공하고 있습니다 : 당신이 XQuery에 대한 지원이없는 경우

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> 

3.0 : 일부 엔진은 유사한 구현 정의 함수를 제공하거나 Java 코드와 같은 백엔드 함수를 사용할 수 있도록 허용합니다.이 경우 XQuery 엔진에 대한 설명서를 읽으십시오.

0

당신이 특정 문자가 캡처 그룹 내에서 발생하지 않습니다 알고 있다면, 당신은 그룹 사이의 문자로 교체 한 후 예를 들어 XQuery를 1

에에 토큰 화 사용할 수 있습니다

tokenize(replace("abc1234", "(.+)(\d+)", "$1-$2"), "-") 
당신은 사용하여 기능이 일반화 할 수

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

페이지로 교체 만들 문자열을 조인 : 그룹 이전과 이후/

확인하려면 대체 모든 것을 제거 같은 attern "$ 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+)")