如何在另一个搜索词中搜索和替换术语

时间:2018-02-11 12:58:07

标签: python regex search vim replace

我有一个在Python中解析一个swagger的api.json文件的URL。

URL看起来像这样,我想用下划线替换短划线,但只在大括号内。

10.147.48.10:8285/pet-store-account/{pet-owner}/version/{pet-type-id}/pet-details-and-name

因此,{pet-owner}将变为{pet_owner},但pet-store-account将保持不变。

我正在寻找一个正则表达式,允许我执行非贪婪的搜索,然后对每个搜索结果进行搜索替换。

我正在寻找Python re方法,但如果你能推荐一个Vim one liner,我也将不胜感激。

预期的最终结果是:

10.147.48.10:8285/pet-store-account/{pet_owner}/version/{pet_type_id}/pet-details-and-name

6 个答案:

答案 0 :(得分:2)

前提是您希望所有' {...}'要保持一致的块,您可以使用尾随上下文来确定给定的破折号是否在块内,实际上只是要求它跟随' ...}'在哪里'。'不是' {'

in_channel

...

exp = re.compile(r'(?=[^{]*})-')

答案 1 :(得分:2)

在Vim中使用lookaheadlookbehind

s/\({[^}]*\)\@<=-\([^{]*}\)\@=/_/g

该模式有三个部分:

\({[^}]*\)\@<=匹配,但不消耗,一个左大括号,后面跟着一个大括号,紧接在下一个部分后面。

-匹配连字符。

\([^{]*}\)\@=匹配,但不会消耗除了前括号之外的任何东西,后面跟一个右括号,紧接在前一部分之前。

在Python正则表达式中不能完全遵循相同的技术,因为它们只允许固定宽度的外观。

<强>结果:

之前

outside-braces{inside-braces}out-again{in-again}out-once-more{in-once-more}

outside-braces{inside_braces}out-again{in_again}out-once-more{in_once_more}

因为它在连字符之前和之后检查正确位置的大括号,所以这个解决方案(与其他仅使用前瞻断言的方案不同)在无法匹配的大括号中表现得非常明显:

之前

b-c{d-e{f-g}h-i
b-c{d-e}f-g}h-i
b-c{d-e}f-g{h-i
b-c}d-e{f-g}h-i

b-c{d-e{f_g}h-i
b-c{d_e}f-g}h-i
b-c{d_e}f-g{h-i
b-c}d-e{f_g}h-i

答案 2 :(得分:1)

Vim中的解决方案:

%s/\({.*\)\@<=-\(.*}\)\@=/_/g

匹配模式的说明:

\({.*\)\@<=-\(.*}\)\@=

\({.*\)\@<=                 Forces the match to have a {.* behind 

           -                Specifies a dash (-) as the match

            \(.*}\)\@=      Forces the match to have a .*} ahead

答案 3 :(得分:1)

使用两步法:

import re

url = "10.147.48.10:8285/pet-store-account/{pet-owner}/version/{pet-type-id}/pet-details-and-name"

rx = re.compile(r'{[^{}]+}')

def replacer(match):
    return match.group(0).replace('-', '_')

url = rx.sub(replacer, url)
print(url)

哪个收益

10.147.48.10:8285/pet-store-account/{pet_owner}/version/{pet_type_id}/pet-details-and-name

这会查找成对的{},并将每个-替换为_
<小时/> 编辑:对于一线大师:

url = re.sub(r'{[^{}]+}',
        lambda x: x.group(0).replace('-', '_'),
        url)

答案 4 :(得分:0)

使用python lookahead忽略括号{}中包含的字符串:

说明

(?=...): 匹配如果...匹配下一个,但不消耗任何字符串。这称为先行断言。例如,Isaac (?=Asimov)只有在跟随'Asimov'时才匹配'Isaac'。

<强>解决方案

a = "10.147.48.10:8285/pet-store-account/**{pet-owner}**/version/**{pet-type-id}**/pet-details-and-name"
import re
re.sub(r"(?=[^{]*})-", "_", a)

<强>输出:

'10.147.48.10:8285/pet-store-account/**{pet_owner}**/version/**{pet_type_id}**/pet-details-and-name'

答案 5 :(得分:0)

在Vim中另一种方法是使用sub-replace-expression:

:%s/{\zs[^}]*\ze}/\=substitute(submatch(0),'-','_','g')/g

使用\zs\ze我们设置{和{}之间的匹配}个字符。使用\={expr}会将{expr}评估为每次替换的替代。在整个匹配substitute({text}, {pat}, {replace}, {flag})上使用VimScripts替换函数submatch(0),将-转换为_

如需更多帮助,请参阅:

:h sub-replace-expression
:h /\zs
:h submatch()
:h substitute()