Подтвердить что ты не робот

Вставка символа в определенном месте в строке

Я хотел бы добавить дополнительный символ (или новую строку) в определенном месте в строке. Например, я хочу вставить d в четвертое место в abcefg, чтобы получить abcdefg.

Теперь я использую:

old <- "abcefg"
n <- 4
paste(substr(old, 1, n-1), "d", substr(old, n, nchar(old)), sep = "")

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

4b9b3361

Ответ 1

Вы можете сделать это с помощью регулярных выражений и gsub.

gsub('^([a-z]{3})([a-z]+)$', '\\1d\\2', old)
# [1] "abcdefg"

Если вы хотите сделать это динамически, вы можете создать выражения с помощью paste:

letter <- 'd'
lhs <- paste0('^([a-z]{', n-1, '})([a-z]+)$')
rhs <- paste0('\\1', letter, '\\2')
gsub(lhs, rhs, old)
# [1] "abcdefg"

в соответствии с комментарием DWin, вы можете захотеть, чтобы это было более общим.

gsub('^(.{3})(.*)$', '\\1d\\2', old)

Таким образом, любые три символа будут соответствовать, а не только строчные буквы. DWin также предлагает использовать sub вместо gsub. Таким образом, вам не нужно беспокоиться о ^, так как sub будет соответствовать только первому экземпляру. Но мне нравится быть явным в регулярных выражениях и только перейти к более общим, как я их понимаю, и найти необходимость в большей общности.


как отметил Грег Сноу, вы можете использовать другую форму регулярного выражения, которая выглядит за спинами:

sub( '(?<=.{3})', 'd', old, perl=TRUE )

и может также построить мой динамический gsub выше, используя sprintf, а не paste0:

lhs <- sprintf('^([a-z]{%d})([a-z]+)$', n-1) 

или для его регулярного выражения sub:

lhs <- sprintf('(?<=.{%d})',n-1)

Ответ 2

@Ответ Justin - это то, как я на самом деле подходил к этому из-за его гибкости, но this также может быть забавным.

Вы можете обрабатывать строку как "формат фиксированной ширины" и указать, куда вы хотите вставить свой символ:

paste(read.fwf(textConnection(old), 
               c(4, nchar(old)), as.is = TRUE), 
      collapse = "d")

Особенно приятным является вывод при использовании sapply, так как вы видите исходную строку как "имя".

newold <- c("some", "random", "words", "strung", "together")
sapply(newold, function(x) paste(read.fwf(textConnection(x), 
                                          c(4, nchar(x)), as.is = TRUE), 
                                 collapse = "-WEE-"))
#            some          random           words          strung        together 
#   "some-WEE-NA"   "rand-WEE-om"    "word-WEE-s"   "stru-WEE-ng" "toge-WEE-ther" 

Ответ 3

stringi пакет для спасения еще раз! Самое простое и элегантное решение среди представленных.

Функция

stri_sub позволяет извлекать части строки и подставлять ее части следующим образом:

x <- "abcde"
stri_sub(x, 1, 3) # from first to third character
# [1] "abc"
stri_sub(x, 1, 3) <- 1 # substitute from first to third character
x
# [1] "1de"

Но если вы это сделаете:

x <- "abcde"
stri_sub(x, 3, 2) # from 3 to 2 so... zero ?
# [1] ""
stri_sub(x, 3, 2) <- 1 # substitute from 3 to 2 ... hmm
x
# [1] "ab1cde"

тогда никакие символы не будут удалены, а новые будут вставлены. Разве это не круто?:)

Ответ 4

Ваш первоначальный способ сделать это (например, разделение строки по индексу и вставку в вставленный текст) можно было бы превратить в такую ​​общую функцию:

split_str_by_index <- function(target, index) {
  index <- sort(index)
  substr(rep(target, length(index) + 1),
         start = c(1, index),
         stop = c(index -1, nchar(target)))
}

#Taken from https://stat.ethz.ch/pipermail/r-help/2006-March/101023.html
interleave <- function(v1,v2)
{
  ord1 <- 2*(1:length(v1))-1
  ord2 <- 2*(1:length(v2))
  c(v1,v2)[order(c(ord1,ord2))]
}

insert_str <- function(target, insert, index) {
  insert <- insert[order(index)]
  index <- sort(index)
  paste(interleave(split_str_by_index(target, index), insert), collapse="")
}

Пример использования:

> insert_str("1234567890", c("a", "b", "c"), c(5, 9, 3))
[1] "12c34a5678b90"

Это позволяет вставить вектор символов в местах, заданных вектором индексов. Функции split_str_by_index и interleave также полезны сами по себе.

Изменить:

Я пересмотрел код, чтобы использовать индексы в любом порядке. Раньше индексы должны были быть в порядке возрастания.

Ответ 5

Я создал пользовательскую функцию под названием substr1, чтобы справиться с извлечением, заменой и вставкой символов в строку. Запускайте эти коды в начале каждого сеанса. Не стесняйтесь попробовать и сообщите мне, нужно ли его улучшить.

# extraction
substr1 <- function(x,y) {
  z <- sapply(strsplit(as.character(x),''),function(w) paste(na.omit(w[y]),collapse=''))
  dim(z) <- dim(x)
  return(z) }

# substitution + insertion
`substr1<-` <- function(x,y,value) {
  names(y) <- c(value,rep('',length(y)-length(value)))
  z <- sapply(strsplit(as.character(x),''),function(w) {
    v <- seq(w)
    names(v) <- w
    paste(names(sort(c(y,v[setdiff(v,y)]))),collapse='') })
  dim(z) <- dim(x)
  return(z) }

# demonstration
abc <- 'abc'
substr1(abc,1)
# "a"
substr1(abc,c(1,3))
# "ac"
substr1(abc,-1)
# "bc"
substr1(abc,1) <- 'A'
# "Abc"
substr1(abc,1.5) <- 'A'
# "aAbc"
substr1(abc,c(0.5,2,3)) <- c('A','B')
# "AaB"