【问题标题】:How to search for and replace a term within another search term如何在另一个搜索词中搜索和替换一个词
【发布时间】:2018-02-11 12:58:07
【问题描述】:

我有一个从 Python 中解析 swagger 的 api.json 文件得到的 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 单行,我也将不胜感激。

预期的最终结果是:

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

【问题讨论】:

标签: python regex search vim replace


【解决方案1】:

在 Vim 中使用 lookaheadlookbehind

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

模式分为三个部分:

\({[^}]*\)\@&lt;= 匹配但不消耗左大括号后跟除右大括号以外的任何内容,紧跟在下一部分之后。

- 匹配连字符。

\([^{]*}\)\@= 匹配但不消耗除左大括号外的任何内容,后跟右大括号,紧接在前一部分之前。

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

结果:

之前

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

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

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

    ...

    substituted_url = re.sub(exp,'_',url_string)
    

    【讨论】:

      【解决方案3】:

      Vim 中的解决方案:

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

      匹配模式说明:

      \({.*\)\@<=-\(.*}\)\@=
      
      \({.*\)\@<=                 Forces the match to have a {.* behind 
      
                 -                Specifies a dash (-) as the match
      
                  \(.*}\)\@=      Forces the match to have a .*} ahead
      

      【讨论】:

      • 谢谢塞尔吉奥。像魅力一样工作。
      • @RaamEE 很高兴它有帮助。
      【解决方案4】:

      使用两步法:

      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)
      

      【讨论】:

      • 谢谢@Jan。正是我需要的。
      【解决方案5】:

      使用python前瞻忽略大括号{}中括起来的字符串:

      说明:

      (?=...): 如果 ... 匹配下一个则匹配,但不使用任何字符串。这称为前瞻断言。例如,Isaac (?=Asimov) 将匹配 'Isaac ',前提是它后面跟着 'Asimov'。

      解决方案

      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'
      

      【讨论】:

        【解决方案6】:

        在 Vim 中的另一种方法是使用子替换表达式:

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

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

        如需更多帮助,请参阅:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-14
          • 2016-03-08
          • 2011-10-13
          • 2018-03-17
          • 2016-07-15
          • 1970-01-01
          相关资源
          最近更新 更多