由于似乎对这个问题的答案很感兴趣,我想我会为后代写一个替代的正则表达式方法。
使用“gregexpr”函数,您可以搜索模式并使用生成的位置匹配和匹配长度来调用原始向量中要更改的值。使用正则表达式的优点是我们可以明确地知道我们想要匹配哪些模式,因此,我们不需要担心任何排除情况。
注意:以下示例按书面形式工作,因为我们假设是个位数的值。我们可以轻松地将其调整为其他模式,但我们可以采用单个字符的小捷径。如果我们想对可能的多位值执行此操作,我们会希望添加一个分隔符作为第一个连接(“粘贴”)函数的一部分。
编码
str.values <- paste(data, collapse="") # String representation of vector
str.matches <- gregexpr("1[0]{1,3}1", str.values) # Pattern 101/1001/10001
data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 1 # Replace zeros with ones
str.matches <- gregexpr("2[0]{1,3}2", str.values) # Pattern 202/2002/20002
data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 2 # Replace zeros with twos
第 1 步:制作一个包含所有数据值的字符串。
str.values <- paste(data, collapse="")
# "11100112220002110102"
这会将数据折叠成一个长字符串,因此我们可以在其上使用正则表达式。
第 2 步:应用正则表达式来查找字符串中任何匹配项的位置和长度。
str.matches <- gregexpr("1[0]{1,3}1", str.values)
# [[1]]
# [1] 3 16
# attr(,"match.length")
# [1] 4 3
# attr(,"useBytes")
# [1] TRUE
在这种情况下,我们使用正则表达式来查找第一个模式,即一到三个零 ( [0]{2,}
),两边各有一个 ( 1[0]{1,3}1
)。我们必须匹配整个模式,以防止必须检查两端是否匹配。我们将在下一步中减去这些末端。
第 3 步:将 1 写入原始向量中的所有匹配位置。
data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 1
# 1 1 1 1 1 1 1 2 2 2 0 0 0 2 1 1 1 1 0 2
我们在这里一次性完成几个步骤。首先,我们从正则表达式中匹配的数字创建一个数字序列列表。在这种情况下,有两个匹配项,它们从索引 3 和 16 开始,分别长 4 和 3 项。这意味着我们的零点位于索引 (3+1):(3-2+4) 或 4:5 以及 (16+1):(16-2+3) 或 17:17。我们再次使用“折叠”选项连接(“粘贴”)这些序列,以防有多个匹配项。然后,我们使用第二个连接将序列放入 combine ( c()
) 函数中。使用 'eval' 和 'parse' 函数,我们将此文本转换为代码并将其作为索引值传递给 [data] 数组。我们将所有的都写入这些位置。
步骤 x:对每个模式重复。在这种情况下,我们需要进行第二次搜索,找到一到三个两边都有二的零,然后运行与步骤 3 相同的语句,但分配二,而不是一。
str.matches <- gregexpr("2[0]{1,3}2", str.values)
# [[1]]
# [1] 10
# attr(,"match.length")
# [1] 5
# attr(,"useBytes")
# [1] TRUE
data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 2
# 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2
更新:我意识到原来的问题是连续匹配一到三个零,而不是我写入原始代码的“两个或更多”。我已经更新了正则表达式和解释,尽管代码保持不变。