【问题标题】:can regex alternation be used in replace?可以在替换中使用正则表达式替换吗?
【发布时间】:2017-02-05 13:56:54
【问题描述】:

我怀疑这是可能的,但我还没有找到任何可以明确表示不可能的东西。但是有没有办法在搜索和替换正则表达式中构建并行交替?因此,例如,如果我想用它们的缩写替换街道类型,我可以这样做:

s/(STREET|AVENUE|BOULEVARD)/(ST|AVE|BLVD)/ 

没有替换整个rhs?还是我真的必须为每种街道类型分别替换?

【问题讨论】:

  • 语言?您可以通过调用函数在 Perl 和 Python 中执行此操作。
  • 您使用什么语言?许多语言允许你在替换时使用一个函数,然后它可以根据匹配的字符串提供不同的替换。例如。 PHP preg_replace_callback().
  • 如果您在文本编辑器中执行此操作,则可能是不可能的。
  • 也可以在 Dreamweaver 中完成 (?:(ST)REET|(AVE)NUE|(B)OU(L)E(V)AR(D)), $1$2$3$4$5$6。知道哪里会对这个问题有很大帮助..

标签: regex


【解决方案1】:

嗯,前两个子字符串并不太难:

import re

s = 'street'; a = 'avenue'; b = 'boulevard'

re.sub(r'(str)eet|(ave)nue|(boulevard)', r'\1 \2 \3', s)
re.sub(r'(str)eet|(ave)nue|(boulevard)', r'\1 \2 \3', a)
re.sub(r'(str)eet|(ave)nue|(boulevard)', r'\1 \2 \3', b)

最后三行返回匹配项以及未匹配组的空格。我认为如果上面的正则表达式捕获它,可能需要对字符串进行进一步处理才能从'boulevard'中获取'blvd'。不过这是合理的,因为从 'boulevard' 中提取一组子字符串是与捕获和替换一组备用正则表达式中的一个不同的问题。

也许,由于这种方式已经需要删除空格的额外步骤,因此可以执行以下操作:

#with boulevard
new_str = re.sub(r'(str)eet|(ave)nue|(b)oulevard', r'\1 \2 \3lvd', b)
re.sub(r'\s+|\blvd', '', new_str)

#with avenue
new_str = re.sub(r'(str)eet|(ave)nue|(b)oulevard', r'\1 \2 \3lvd', a)
re.sub(r'\s+|\blvd', '', new_str)

不过代码看起来有点搞笑。

【讨论】:

  • @ClasG,正如我所说,很有趣(不好)。这就是为什么我添加了一行代码,它删除了任何空格或序列“lvd”,单词边界紧邻左侧。
  • @ClasG,啊,我明白了。我的测试用例(变量 s、a 和 b)没有涵盖完整的句子,我认为这很不现实。
【解决方案2】:

这不是漂亮,但它会完成工作:

替换

(?:(ST)REET|(AVE)NUE|(B)OU(L)E(V)AR(D))

\1\2\3\4\5\6

它匹配单词,捕获相关部分。替换为所有捕获组并插入相关部分。

See it here at regex101.

【讨论】:

  • 那么,我们能否加大对并非严格缩写的并行替换的投入? - 这样 /(FIRST|SECOND|THIRD)/ 可以替换为 1ST|2ND|3RD
  • 不是没有编程逻辑(据我所知),(或者像提到的,Notepad++ 和喜欢......)
【解决方案3】:

为了好玩,这三个词只在 PCRE/Perl/Python 正则表达式模块/npp 中:

(?:\G(?!^)|\b(?=(?:STREET|AVENUE|BOULEVARD)\b))[A-Z]*?\K(?:TREE|E(?:NU)?|OU|AR)\B

用空字符串替换。

demo

或者这个:

\G[A-Z]*?(?>\W*\b(?>\w+\W+)*?(?=(?:STREET|AVENUE|BOULEVARD)\b))?[A-Z]*?\K(?:TREE\B|E(?:NU)?\B|OU\B|AR\B)

demo

【讨论】:

    【解决方案4】:

    在 Python 中,您可以像这样使用对字典的回调:

    >>> abs={'STREET':'ST', 'AVENUE':'AVE','BOULEVARD':'BLVD'}
    >>> re.sub(r'(STREET|AVENUE|BOULEVARD)', lambda m: abs[m.group(1)], 'Fourth STREET')
    'Fourth ST'
    

    在 Perl 中,你可以这样做:

    use strict;
    use warnings;
    
    my %abs=(
        'STREET', 'ST',
        'AVENUE' ,'AVE',
        'BOULEVARD', 'BLVD'
    );
    $_='Fourth STREET';
    s/(STREET)|(AVENUE)|(BOULEVARD)/$abs{$1}/ && print;
    

    【讨论】:

      【解决方案5】:

      这取决于您使用的语言或工具。比如使用Notepad++,可以替换

      (STREET)|(AVENUE)|(BOULEVARD)
      

      与:

      (?1ST)(?2AVE)(?3BLVD)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-06-01
        • 2010-11-02
        • 1970-01-01
        • 2020-11-05
        • 1970-01-01
        • 2015-01-24
        相关资源
        最近更新 更多