【问题标题】:How to replace specific trailing characters but block the first two letters如何替换特定的尾随字符但阻止前两个字母
【发布时间】:2020-07-11 07:32:28
【问题描述】:

我想通过用下划线替换所有尾随的 X 和 Y 来协调字符串。由于这些字符串的长度各不相同,因此我编写了以下正常工作的正则表达式。但是,前 两个 字符应始终保持原样。我知道我可以使用substr()paste0() 作为解决方法,但是如何在正则表达式中包含这个“不替换前两个字符”?

x <- c("AXZ", "AZXYYX", "HZX_Y", "BXX", "XYX_")

# replaces all trailing X / Y
gsub("[XY](?=[XY_]*$)", "_", x, perl = TRUE)
#> [1] "AXZ"    "AZ____" "HZ___"  "B__"    "____"

# blocks first character
gsub("(?<!^)[XY](?=[XY_]*$)", "_", x, perl = TRUE)
#> [1] "AXZ"    "AZ____" "HZ___"  "B__"    "X___"

# desired output
c("AXZ", "AZ____", "HZ___", "BX_", "XY__")
#> [1] "AXZ"    "AZ____" "HZ___"  "BX_"    "XY__"

我已经设法排除了第一个字母,所以我想这应该很容易解决。

【问题讨论】:

    标签: r regex regex-lookarounds gsub


    【解决方案1】:

    以下方法似乎有效:

    gsub("(?<=.{2})[XY](?=[XY_]*$)", "_", x, perl=TRUE)
    
    [1] "AXZ"    "AZ____" "HZ___"  "BX_"    "XY__"
    

    下面是正则表达式模式的解释,它使用环视来强制执行正确的替换:

    (?<=.{2})        lookbehind and assert there exist at least 2 preceding characters;
                     this ensures replacement will never be made on first 2 characters
    [XY]             match any of X or Y
    (?=[XY_]*$)      lookahead and assert that previous X/Y/_ is only followed
                     by more X/Y/_ until the end of the string
    

    请注意,我们一次用下划线替换一个字符,但我们使用gsub,以便进行所有必要的替换。

    【讨论】:

    • 感谢您的解决方案和解释!这看起来既整洁又经济!我只是认为我们不必用下划线替换下划线,因此(?&lt;=.{2})[XY](?=[XY_]*$) 应该没问题?
    • @mnist 是的,你是对的,我已经更新了我的答案。
    • 绝妙的解决方案!
    【解决方案2】:

    您可以使用(*SKIP)(*FAIL) 跳过前两个字符:

    x <- c("AXZ", "AZXYYX", "HZX_Y", "BXX", "XYX_")
    
    gsub("^.{2}(*SKIP)(*FAIL)|[XY](?=[XY_]*$)", "_", x, perl = TRUE)
    

    产量

    [1] "AXZ"    "AZ____" "HZ___"  "BX_"    "XY__"  
    

    a demo on regex101.com

    【讨论】:

    • 感谢您的解决方案!你能解释一下正则表达式是如何工作的吗?尤其是SKIP和FAIL的组合和|达到。
    • 好答案。您可能希望将链接更改为 this,这只是您的链接,其中包含显示的替换项(.../2 而不是 .../1)。
    【解决方案3】:

    一种方法是捕获前两个字符并重复它们。您可以在替换字符串中使用 '\1'、'\2' 等来分别引用第一个、第二个等捕获组。这里我们只有一个捕获组。

    sub("(..)[XY]+$)", "\\1_", x, perl = TRUE)
    

    【讨论】:

    • @mnist 错误是因为美元符号后面的)应该省略。
    • 那么结果不理想
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 2015-12-21
    • 1970-01-01
    • 2021-03-31
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多