【问题标题】:Replace words in an unstructured text file using a for loop使用 for 循环替换非结构化文本文件中的单词
【发布时间】:2019-03-20 18:48:15
【问题描述】:

我有一个非常非结构化的文本文件,我使用 readLines 读取。我想将某些字符串更改为变量中的另一个字符串(下面称为“新”)。

下面,我希望操纵文本包含所有术语:“一”、“二”、“三”和“四”一次,而不是“更改”字符串。但是,正如您所见, sub 更改了每个元素中的第一个模式,但我需要代码忽略有带引号的新字符串。

请参阅下面的示例代码和数据。

 #text to be changed
 text <- c("TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT change",
        "TEXT TEXT TEXT change TEXT TEXT TEXT TEXT TEXT change", 
        "TEXT TEXT TEXT change TEXT TEXT TEXT TEXT")

 #Variable containing input for text
 new <- c("one", "two", "three", "four")
 #For loop that I want to include 
 for (i in 1:length(new)) {

   text  <- sub(pattern = "change", replace = new[i], x = text)

 }
 text

【问题讨论】:

  • 你需要 text

标签: r loops for-loop


【解决方案1】:

这个怎么样?逻辑是,敲掉一个字符串,直到它不再有change。在每个“命中”(找到change 的位置)上,沿着new 向量移动。

text <- c("TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT change",
          "TEXT TEXT TEXT change TEXT TEXT TEXT TEXT TEXT change", 
          "TEXT TEXT TEXT change TEXT TEXT TEXT TEXT")

#Variable containing input for text
new <- c("one", "two", "three", "four")
new.i <- 1

for (i in 1:length(text)) {
  while (grepl(pattern = "change", text[i])) {
    text[i] <- sub(pattern = "change", replacement = new[new.i], x = text[i])
    new.i <- new.i + 1
  }
}
text

[1] "TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT one" 
[2] "TEXT TEXT TEXT two TEXT TEXT TEXT TEXT TEXT three"
[3] "TEXT TEXT TEXT four TEXT TEXT TEXT TEXT" 

【讨论】:

    【解决方案2】:

    这是另一个使用gregexpr()regmatches() 的解决方案:

    #text to be changed
    text <- c("TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT change",
              "TEXT TEXT TEXT change TEXT TEXT TEXT TEXT TEXT change",
              "TEXT TEXT TEXT change TEXT TEXT TEXT TEXT")
    
    #Variable containing input for text
    new <- c("one", "two", "three", "four")
    
    # Alter the structure of text
    altered_text <- paste(text, collapse = "\n")
    
    # So we can use gregexpr and regmatches to get what you want
    matches <- gregexpr("change", altered_text)
    regmatches(altered_text, matches) <- list(new)
    
    # And here's the result
    cat(altered_text)
    #> TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT one
    #> TEXT TEXT TEXT two TEXT TEXT TEXT TEXT TEXT three
    #> TEXT TEXT TEXT four TEXT TEXT TEXT TEXT
    
    # Or, putting the text back to its old structure
    # (one element for each line)
    unlist(strsplit(altered_text, "\n"))
    #> [1] "TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT one" 
    #> [2] "TEXT TEXT TEXT two TEXT TEXT TEXT TEXT TEXT three"
    #> [3] "TEXT TEXT TEXT four TEXT TEXT TEXT TEXT"
    

    我们可以这样做,因为gregexpr() 可以在“更改”的文本中找到所有匹配项;来自help("gregexpr")

    regexpr 返回一个与给出的文本长度相同的整数向量 第一场比赛的起始位置....

    gregexpr 返回一个与 text 的每个元素长度相同的列表 它与正则表达式的返回值形式相同,除了 每个(不相交的)匹配的起始位置已给出。

    (强调)。

    那么regmatches()可以用来提取gregexpr()找到的匹配或者替换它们;来自help("regmatches")

    用法

    regmatches(x, m, invert = FALSE)
    regmatches(x, m, invert = FALSE)

    ...

    价值
    一个具有合适替换值的对象,用于匹配的或 不匹配的子字符串(请参阅详细信息)。

    ...

    详情

    替换功能可用于替换匹配的或 不匹配的子串。对于矢量匹配数据,如果 invert 为 FALSE, value 应该是一个字符向量,其长度为匹配的数量 m中的元素否则,它应该是一个字符向量列表 长度与 m 相同,每个长度与替换次数一样长 需要。

    【讨论】:

    • 我喜欢这种方法。我看到的唯一警告(这就是为什么我没有走类似的串联路径)是某些字符串中可能存在\n,此时事情会在最后一步击中众所周知的粉丝。跨度>
    【解决方案3】:

    使用strsplit的另一种方法:

    tl <- lapply(text, function(s) strsplit(s, split = " ")[[1]])
    df <- stack(setNames(tl, seq_along(tl)))
    
    ix <- df$values == "change"
    df[ix, "values"] <- new
    tapply(df$values, df$ind, paste, collapse = " ")
    

    给出:

                                                      1 
     "TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT one" 
                                                      2 
    "TEXT TEXT TEXT two TEXT TEXT TEXT TEXT TEXT three" 
                                                      3 
              "TEXT TEXT TEXT four TEXT TEXT TEXT TEXT"
    

    此外,您可以将tapply 调用包装在unname 中:

     unname(tapply(df$values, df$ind, paste, collapse = " "))
    

    给出:

    [1] "TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT one" 
    [2] "TEXT TEXT TEXT two TEXT TEXT TEXT TEXT TEXT three"
    [3] "TEXT TEXT TEXT four TEXT TEXT TEXT TEXT"
    

    如果您只想使用new 的元素一次,您可以将代码更新为:

    newnew <- new[1:3]
    
    ix <- df$values == "change"
    df[ix, "values"][1:length(newnew)] <- newnew
    unname(tapply(df$values, df$ind, paste, collapse = " "))
    

    您可以进一步更改此设置,以考虑替换位置多于需要替换的位置(模式的出现,在示例中为 change)的情况:

    newnew2 <- c(new, "five")
    
    tl <- lapply(text, function(s) strsplit(s, split = " ")[[1]])
    df <- stack(setNames(tl, seq_along(tl)))
    
    ix <- df$values == "change"
    df[ix, "values"][1:pmin(sum(ix),length(newnew2))] <- newnew2[1:pmin(sum(ix),length(newnew2))]
    unname(tapply(df$values, df$ind, paste, collapse = " "))
    

    【讨论】:

      猜你喜欢
      • 2021-10-13
      • 2013-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-24
      • 2018-06-01
      • 2017-08-25
      • 1970-01-01
      相关资源
      最近更新 更多