【问题标题】:regex for replacement of specific character outside parenthesis only正则表达式仅用于替换括号外的特定字符
【发布时间】:2021-08-25 09:45:06
【问题描述】:

我正在寻找正则表达式(最好在 R 中),它可以用 ;; 替换(任意数量的)特定字符,比如 ;,但只有当括号内的 不存在 @987654324 @ 在文本字符串中。

注意:1.括号内也可能有多个替换字符

2。数据/向量中没有嵌套括号

例子

  • text;othertext 替换为 text;;othertext
  • text;other(texttt;some;someother);more 将替换为text;;other(texttt;some;someother);;more(即 ; 仅在 () 之外用替换文本替换)

如果需要澄清,我会尽力解释

in_vec <- c("abcd;ghi;dfsF(adffg;adfsasdf);dfg;(asd;fdsg);ag", "zvc;dfasdf;asdga;asd(asd;hsfd)", "adsg;(asdg;ASF;DFG;ASDF;);sdafdf", "asagf;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;sdfa")

in_vec
#> [1] "abcd;ghi;dfsF(adffg;adfsasdf);dfg;(asd;fdsg);ag"
#> [2] "zvc;dfasdf;asdga;asd(asd;hsfd)"             
#> [3] "adsg;(asdg;ASF;DFG;ASDF;);sdafdf"           
#> [4] "asagf;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;sdfa"

预期输出(手动计算)

[1] "abcd;;ghi;;dfsF(adffg;adfsasdf);;dfg;;(asd;fdsg);;ag" 
[2] "zvc;;dfasdf;;asdga;;asd(asd;hsfd)"             
[3] "adsg;;(asdg;ASF;DFG;ASDF;);;sdafdf"            
[4] "asagf;;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;;sdfa"

【问题讨论】:

  • 请告知是否需要澄清
  • 添加一些您尝试过的代码可能有助于使您所考虑的过程更加清晰
  • 我也想知道上游是否有解决方案——文本是否必须以这种方式开始?还是您无法控制的情况?
  • @nicola,数据/向量中没有嵌套括号。
  • @AnilGoyal 太好了,我认为您应该将此信息添加到问题中,因为它与构建解决方案非常相关(使用嵌套括号会更难)。

标签: r regex gsub string-substitution


【解决方案1】:

您可以将gsub;(?![^(]*\\)) 一起使用:

gsub(";(?![^(]*\\))", ";;", in_vec, perl=TRUE)
#[1] "abcd;;ghi;;dfsF(adffg;adfsasdf);;dfg;;(asd;fdsg);;ag"
#[2] "zvc;;dfasdf;;asdga;;asd(asd;hsfd)"                   
#[3] "adsg;;(asdg;ASF;DFG;ASDF;);;sdafdf"                  
#[4] "asagf;;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;;sdfa"       

; 找到 ;, (?!) .. Negative Lookahead (当它不匹配时进行替换), [^(] .. 除了(, * 重复前面的 0 到 n次,\\) .. 流经)

或者

gsub(";(?=[^)]*($|\\())", ";;", in_vec, perl=TRUE)
#[1] "abcd;;ghi;;dfsF(adffg;adfsasdf);;dfg;;(asd;fdsg);;ag"
#[2] "zvc;;dfasdf;;asdga;;asd(asd;hsfd)"                   
#[3] "adsg;;(asdg;ASF;DFG;ASDF;);;sdafdf"                  
#[4] "asagf;;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;;sdfa"       

; 找到 ;(?=) .. 正向前瞻(匹配时进行替换)、[^)] .. 除了 )* 之外的所有内容重复前面的 0 到 n 次, ($|\\() .. 匹配结束 $(.

或使用gregexprregmatches 提取() 之间的部分并在不匹配的子字符串中进行替换:

x <- gregexpr("\\(.*?\\)", in_vec)  #Find the part between ( and )
mapply(function(a, b) {
  paste(matrix(c(gsub(";", ";;", b), a, ""), 2, byrow=TRUE), collapse = "")
}, regmatches(in_vec, x), regmatches(in_vec, x, TRUE))
#[1] "abcd;;ghi;;dfsF(adffg;adfsasdf);;dfg;;(asd;fdsg);;ag"
#[2] "zvc;;dfasdf;;asdga;;asd(asd;hsfd)"                   
#[3] "adsg;;(asdg;ASF;DFG;ASDF;);;sdafdf"                  
#[4] "asagf;;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;;sdfa"       

但它们都只适用于简单的打开(关闭)组合。

【讨论】:

  • 感谢您的解决方案。 +1 已经。要求就是这样(打开和关闭组合)。但是是否有任何正则表达式可以匹配此组合之外的特定字符?
  • 是的,( or ) 前后的字符数(被替换)不确定
  • 像魅力一样工作。希望我能两次投票给你。 :) 接受这一点。同时你能解释一下你的正则表达式吗?
  • 只是出于好奇,如果输入包含嵌套括号怎么办?例如,假设您有asagf;(fafgf;(sadg);sdag;a;gddfg;fd)gsfg;sdfa,而所需的输出是asagf;;(fafgf;(sadg);sdag;a;gddfg;fd)gsfg;;sdfa(您的解决方案将外部( 内的第一个; 加倍)。
  • @nicola 也许问一个关于这个话题的新问题。当您将 x &lt;- gregexpr("\\(.*?\\)", in_vec) 更改为 x &lt;- gregexpr("(\\(([^()]|(?R))*\\))", in_vec, perl=TRUE) 时,它可能适用于嵌套括号。
【解决方案2】:

虽然问题可以用正则表达式解决,但使用简单的函数可能更直接、更容易理解。

replace_semicolons_outside_parentheses <- function(raw_string) {
    """Replace ; with ;; outside of parentheses"""

    processed_string <- ""
    n_open_parentheses <- 0

    # Loops over characters in raw_string
    for (char in strsplit(raw_string, "")[[1]]) {

        # Update the net number of open parentheses
        if (char == "(") {
            n_open_parentheses <- n_open_parentheses + 1
        } else if (char == ")") {
            n_open_parentheses <- n_open_parentheses - 1
        }

        # Replace ; with ;; outside of parentheses
        if (char == ";" && n_open_parentheses == 0) {
            processed_string <- paste0(processed_string, ";;")
        } else {
            processed_string <- paste0(processed_string, char)
        }      
    }
    return(processed_string)
}

请注意,上面的函数也适用于嵌套括号:嵌套括号内的分号不会被替换!可以在一行中获得所需的输出:

out_vec <- lapply(in_vec, replace_semicolons_outside_parentheses)

# 1. 'abcd;;ghi;;dfsF(adffg;adfsasdf);;dfg;;(asd;fdsg);;ag'
# 2. 'zvc;;dfasdf;;asdga;;asd(asd;hsfd)'
# 3. 'adsg;;(asdg;ASF;DFG;ASDF;);;sdafdf'
# 4. 'asagf;;(fafgf;sadg;sdag;a;gddfg;fd)gsfg;;sdfa'

【讨论】:

    【解决方案3】:

    如果没有嵌套括号,请使用以下内容:

    gsub("\\([^()]*\\)(*SKIP)(*FAIL)|;", ";;", in_vec, perl=TRUE)
    

    regex proof

    解释

    --------------------------------------------------------------------------------
      \(                       '(' char
    --------------------------------------------------------------------------------
        [^()]*                   any character except: '(', ')' (0 or
                                 more times (matching the most amount
                                 possible))
    --------------------------------------------------------------------------------
        \)                       ')' char
    --------------------------------------------------------------------------------
      (*SKIP)(*FAIL)           skip current match, search for new one from here
    --------------------------------------------------------------------------------
     |                        OR
    --------------------------------------------------------------------------------
      ;                        ';'
    

    如果有嵌套括号:

    gsub("(\\((?:[^()]++|(?1))*\\))(*SKIP)(*FAIL)|;", ";;", in_vec, perl=TRUE)
    

    regex proof

    解释

    --------------------------------------------------------------------------------
      (                        group and capture to \1:
    --------------------------------------------------------------------------------
        \(                       '('
    --------------------------------------------------------------------------------
        (?:                      group, but do not capture:
    --------------------------------------------------------------------------------
          [^()]++                  any character except: '(', ')' (1 or more times 
                                   (matching the most amount possible, no backtracking))
    --------------------------------------------------------------------------------
         |                         or
    --------------------------------------------------------------------------------
         (?1)                    recursing first group pattern
    --------------------------------------------------------------------------------
        )                        end of grouping
    --------------------------------------------------------------------------------
      \)                         ')' 
    --------------------------------------------------------------------------------  
      )                          end of \1
    --------------------------------------------------------------------------------  
      (*SKIP)(*FAIL)             skip the match, search for next
    --------------------------------------------------------------------------------
      |                         or
    --------------------------------------------------------------------------------
      ;                         ';'
    --------------------------------------------------------------------------------
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多