2016-10-24 19 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

Plain 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:

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.

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+)") 

 Смежные вопросы

  • Нет связанных вопросов^_^