Заменить слова в неструктурированном текстовом файле с помощью цикла for - PullRequest
0 голосов
/ 16 октября 2018

У меня ОЧЕНЬ неструктурированный текстовый файл, который я читаю с помощью 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

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Вот еще одно решение, использующее 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() может найти все совпадения в тексте для слова «изменить»;from help("gregexpr"):

regexpr возвращает целочисленный вектор такой же длины, что и текст, дающий начальную позицию первого совпадения ....

gregexpr возвращает список с тем же самымдлина в виде текста, каждый элемент которого имеет ту же форму, что и возвращаемое значение для regexpr, за исключением того, что указаны начальные позиции каждые (непересекающиеся) совпадения.

(выделениедобавлено).

Затем regmatches() можно использовать либо для извлечения совпадений, найденных с помощью gregexpr() , либо для их замены ;от help("regmatches"):

Использование

совпадений (x, m, инвертировать = FALSE)
совпадений (x, m, инвертировать = FALSE) <- значение </p>

...

значение
объект с подходящими значениями замены для сопоставленных или несовпадающих подстрок (см. Подробности).

...

Подробности

Функция замены может использоваться для замены совпавших или несогласованных подстрок.Для данных совпадения векторов, если инвертирование равно FALSE, значением должен быть символьный вектор с длиной, равной количеству совпадающих элементов в m.В противном случае это должен быть список векторов символов той же длины, что и m, каждый из которых соответствует количеству необходимых замен.

0 голосов
/ 16 октября 2018

Другой подход, использующий 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 только один раз, вы можете обновить кодto:

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 = " "))
0 голосов
/ 16 октября 2018

Как насчет этого?Логика заключается в том, чтобы выбить строку, пока она не перестанет 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" 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...