68

我想在字符串的特定位置插入一个额外的字符(或新字符串)。例如,我想d在第四个位置插入abcefg以获取abcdefg.

现在我正在使用:

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

我可以为这个任务写一个简单的函数,但我只是好奇是否有一个现有的函数。

4

7 回答 7

73

您可以使用正则表达式和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只会匹配第一个实例。但我喜欢在正则表达式中明确表达,并且只在我理解它们并发现需要更多通用性时才转向更一般的表达式。


正如 Greg Snow 所指出的,您可以使用另一种形式的正则表达式来查找匹配项:

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

gsub并且还可以使用sprintf而不是在上面构建我的动态paste0

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

或者他的sub正则表达式:

lhs <- sprintf('(?<=.{%d})',n-1)
于 2012-12-13T16:05:42.227 回答
42

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"

然后不会删除任何字符,但会插入新字符。这不是很酷吗?:)

于 2017-08-17T14:44:25.263 回答
8

@Justin 的答案是我实际处理这个问题的方式,因为它具有灵活性,但这可能是一种有趣的方法。

您可以将字符串视为“固定宽度格式”并指定要插入字符的位置:

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" 
于 2012-12-13T16:18:49.243 回答
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_indexinterleave

编辑:

我修改了代码以允许任何顺序的索引。以前,索引需要按升序排列。

于 2014-08-21T00:00:10.187 回答
2

我制作了一个自定义函数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"
于 2017-11-15T22:19:05.203 回答
2

我花了一些时间来理解正则表达式,之后我找到了我的数字

最终结果是

old <- "89580000"
gsub('^([0-9]{5})([0-9]+)$', '\\1-\\2', old)
于 2018-01-12T21:31:27.450 回答
0

和你的一样!

首先确保加载 tidyverse 包,然后同时使用 paste0 和 gsub。

这是确切的代码:

paste0(substr(old, 1,3), "d", substr(old,4,6))
于 2022-02-01T06:10:17.980 回答