根据从头到尾的字符数在字符串中插入字符

Insert character in string conditional on number of characters from beginning and end

我有一个字符串列表,例如

myvar
[1] "VT" "AK" "AL2" "CA24" "NY12" 
[6] "AZ6" "WY4"

我想在所有有3个字符的字符串的第二个字符后插入字符“0”,在所有有两个字符的字符串的末尾插入“01”,以获得输出

myvar
[1] "VT01" "AK01" "AL02" "CA24" "NY12" 
[6] "AZ06" "WY04"

我以为我可以使用正则表达式前瞻和后视在一行中完成此操作,但我无法做更多的事情:

sub('(?<=.{2})(?=.{1})', '0', myvar, perl=T)

myvar
[1] "VT" "AK" "AL002" "CA024" "NY012" 
[6] "AZ06" "WY04"

如有任何帮助,我们将不胜感激,

西蒙

我们可以使用 sub 提取数字部分,将字符串转换为 numeric class,将 NA 值(从强制转换)更改为 1,然后使用 sprintf 粘贴非数字 (sub('\d+', ...)) 和格式化数字部分。

 v1 <- as.numeric(sub('\D+', '', myvar))
 v1[is.na(v1)] <- 1
 sprintf('%s%02d', sub('\d+', '', myvar),v1)
 #[1] "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04"

或使用gsubfn。我们为那些没有任何数字元素的元素创建一个ifelse条件并粘贴1。我们匹配gsubfn\d+)中的数字部分,通过格式化替换它 sprintf.

 library(gsubfn)
 gsubfn('\d+', ~sprintf('%02d', as.numeric(x)),
     ifelse(!grepl('\d+', myvar), paste0(myvar, 1), myvar))
 #[1] "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04"

或者稍微更紧凑的版本是使用 sub 将 1 附加到那些没有数字部分的元素

 gsubfn('\d+', ~sprintf('%02d', as.numeric(x)) ,sub('(?<=[A-Z])$', '1', myvar, perl=TRUE))
 #[1] "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04"

或者在没有环视的情况下使它更紧凑,

gsubfn('\d+', ~sprintf('%02d', as.numeric(x)), sub('(\D+)$', '\11', myvar))
#[1] "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04"

关于静态剪切和粘贴的想法:

paste0(substr(myvar, 0, 2), sub("00", "01", gsub(" ", "0", sprintf("% 2s", substr(myvar, 3, 4)))))

# [1] "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04"

使用 substr 获取最后 2 个字符,将它们填充为 2 个字符,将空格替换为 0,然后将 00 替换为 01,粘贴前 2 个字符即可得到结果。


一个衬里(没有正则表达式,因为它们不是必需的,并且根本不能真正有用地确定替换尺寸,除非使用复杂的选择,然后用什么替换):

myvar[nchar(myvar)<4] <- paste0(myvar[nchar(myvar)<4],sprintf(paste0("%0",4-nchar(myvar[nchar(myvar)<4]),"i"),1))

目标是获得一个包含 4 个字符条目的向量,因此对于 4 个字符 (myvar[nchar(myvar)<4]) 以下的所有条目,沿着长度为 4 减去实际条目长度的 0 左填充“1”打印它们。

with 可能有一种方法可以避免对 myvar[nchar(myvar)<4] 的冗余调用,但由于我不习惯,我实际上正在挖掘。

另一种选择(可以是单(长)衬里...):

mapply(function(x, dc_x){
           if(nchar(x)<4) paste0(dc_x[1], "0", ifelse(length(dc_x)-1, dc_x[2], "1")) else x
        }, 
       x=myvar, dc_x=strsplit(myvar,  "(?<=^.{2})", perl=T))
#    VT     AK    AL2   CA24   NY12    AZ6    WY4 
# "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04" 

解释:
dc_x 是一个向量列表,myvar 的每个元素一个,第一项是 myvar 中对应项的第 2 个字符。因此,对于少于 4 个字符的元素,如果只有 2 个字符,则将前 2 个字符粘贴为“01”,如果超过 2 个字符,则粘贴“0”和字符串的其余部分。

您可以将 sub 或 gsub 命令的输出作为另一个 sub 或 gsub 命令的输入。

myvar <- c("VT", "AK", "AL2", "CA24", "NY12",
           "AZ6", "WY4")
sub("^(.{2})$", "\101", sub("^(.{2})(.)$", "\10\2", myvar))
# [1] "VT01" "AK01" "AL02" "CA24" "NY12" "AZ06" "WY04"