代码之家  ›  专栏  ›  技术社区  ›  batteredveg

Regex:替换特定单词后的空格

  •  0
  • batteredveg  · 技术社区  · 2 年前

    我正在尝试(但失败了)编写一个正则表达式(PCRE2),该表达式将在特定单词(即VAN、VON或DE)的第一个实例之后用破折号(-)替换每个空格,该单词本身必须被空格包围。

    例如:

    HENRIETTA VON DER GRAAF
    CAROLINE VAN OOSTEN DE WINKEL
    MARC DE VRIES VAN JONG
    ANNEKA VANHOVEN BAKKER
    JOHN WILKINSON SMITH
    

    将翻译为:

    HENRIETTA VON-DER-GRAAF
    CAROLINE VAN-OOSTEN-DE-WINKEL
    MARC DE-VRIES-VAN-JONG
    ANNEKA VANHOVEN BAKKER (NB: Does not match VAN as not surrounded by spaces)
    JOHN WILKINSON SMITH (NB: No substitution here as pattern not matched)
    

    这是我所能做到的,但它并没有取代比赛后的所有空格:

    \b( VON| VAN| DE)+\s
    

    https://regex101.com/r/s6BC1y/1

    任何建议,不胜感激!

    4 回复  |  直到 2 年前
        1
  •  2
  •   Nick SamSmith1986    2 年前

    您可以使用此regex实现您想要的结果:

    ^(.*? (?:VAN|VON|DE)) |((?<!^)\G\w+) 
    

    这与以下任一项匹配:

    • ^(.*? (?:VAN|VON|DE)) :行首后的最小字符数,后跟空格,以及 VON , VAN 或 DE ,全部捕获在组1中,然后是一个空格;或
    • ((?<!^)\G\w+) :从上次成功匹配的末尾开始的一定数量的单词字符(但不在字符串的开头 \G 通常允许),在第2组中捕获,然后是一个空格

    然后可以将匹配项替换为 $1$2- (只有一个 $1 或 $2 将具有任何内容)。

    Regex演示 regex101

    请注意,正则表达式可以使用 \K 丢弃匹配的前部分,只匹配单词后面的空格:

    ^.*? (?:VAN|VON|DE)\K |(?<!^)\G\w+\K 
    

    那么替换就是 - 。

    Regex演示 regex101

        2
  •  2
  •   InSync Christian C. Salvadó    2 年前

    这可以通过 \G 和 \K :

    (?:                # Match either
      (?<!\S)          #                      but only if it is not preceded by a whitespace,
      (?:VON|VAN|DE)   # 'VON', 'VAN' or 'DE'
    |                  # or
      \G(?!\A)         # the end of the last match
      \S+              # then a sequence of non-whitespace characters.
    )                  # 
    \K\x20             # Forfeit everything we just match, then match a space.
    

    试试看 on regex101.com 。

    由于PCRE2中缺乏对非固定宽度lookbehinds的支持,我们无法执行以下操作,这可以说更容易理解:

    (?<=               # Match a position preceded by
      (?:VON|VAN|DE)   # either of the three words
      (?:\x20\S+)*     # then 0 or more (space + word),
    )                  # 
    \x20               # and a space at that position.
    

    试试看 on regex101.com 。

    \G 匹配上一场比赛结束时的位置 或 整个字符串的开头。幸亏 (?!\A) ,只有当我们匹配了第一个备选方案时,后一个备选方案才会匹配: (?<!\S)(?:VON|VAN|DE) 。

    视觉解释:

    MARC DE VRIES VAN JONG
         ^ Start matching `(?<!\S)(?:VON|VAN|DE)`
    
    MARC DE VRIES VAN JONG
           ^ ...then `\x20`.
    
    MARC DE VRIES VAN JONG
            ^ `(?<!\S)(?:VON|VAN|DE)` doesn't match here; switch to `\S+`
    
    MARC DE VRIES VAN JONG
                 ^ `\x20` is matched.
    
    MARC DE VRIES VAN JONG
                  ^ Back to step 1.
    
    MARC DE VRIES VAN JONG
                      ^ Back to step 3.
    
        3
  •  0
  •   BamGbam    2 年前

    您可以使用以下regex模式来实现所需的结果:

    (?<=[VON|VAN|DE]\s)\s
    

    此正则表达式模式将在第一个由空格包围的“VON”、“VAN”或“DE”实例之后用破折号替换所有空格。我希望它能帮助你。

        4
  •  0
  •   Gilles Quénot ticktalk    2 年前

    使用Perl:

    perl -anE '
        if (/\b(?:VON|VAN|DE)\b/) {
            @a = split /\s+/;
            say $a[0], " ", join "_", @a[1..$#a]
        } else {
            print;
        }
    ' file
    

    HENRIETTA VON_DER_GRAAF
    CAROLINE VAN_OOSTEN_DE_WINKEL
    MARC DE_VRIES_VAN_JONG
    ANNEKA VANHOVEN BAKKER
    JOHN SMITH