我看到过很多使用gsub
提取的版本,但它们大多是处理从左到右或在一次出现后提取。 我想要从右到左匹配,计算四个-
的出现次数,并匹配第3个和第4个出现之间的所有内容。
例如:
string outcome
here-are-some-words-to-try some
a-b-c-d-e-f-g-h-i f
这里是我尝试使用的一些参考:
我看到过很多使用gsub
提取的版本,但它们大多是处理从左到右或在一次出现后提取。 我想要从右到左匹配,计算四个-
的出现次数,并匹配第3个和第4个出现之间的所有内容。
例如:
string outcome
here-are-some-words-to-try some
a-b-c-d-e-f-g-h-i f
这里是我尝试使用的一些参考:
([^-]+)(?:-[^-]+){3}$
可以在regex101.com上查看演示。
R
中,可以这样写:
library(dplyr)
library(stringr)
df <- data.frame(string = c('here-are-some-words-to-try', 'a-b-c-d-e-f-g-h-i', ' no dash in here'), stringsAsFactors = FALSE)
df <- df %>%
mutate(outcome = str_match(string, '([^-]+)(?:-[^-]+){3}$')[,2])
df
并产生
string outcome
1 here-are-some-words-to-try some
2 a-b-c-d-e-f-g-h-i f
3 no dash in here <NA>
x = c("here-are-some-words-to-try", "a-b-c-d-e-f-g-h-i")
sapply(x, function(strings){
ind = unlist(gregexpr(pattern = "-", text = strings))
if (length(ind) < 4){NA}
else{substr(strings, ind[length(ind) - 3] + 1, ind[length(ind) - 2] - 1)}
})
#here-are-some-words-to-try a-b-c-d-e-f-g-h-i
# "some" "f"
你可以尝试将句子分开来写,就像这样
string <- "here-are-some-words-to-try"
# separate all words
val <- strsplit(string, "-")[[1]]
# reverse the order
val rev(val)
# take the 4th element
val[4]
# And using a dataframe
library(tidyverse)
tibble(string = c("here-are-some-words-to-try", "a-b-c-d-e-f-g-h-i")) %>%
mutate(outcome = map_chr(string, function(s) rev(strsplit(s, "-")[[1]])[4]))
另一个选项是确定字符串中元素的位置。这个解决方案与类似问题此处的解决方案重复。
虽然这有点混乱,但已经实现了我想要的,并且可以解决你的问题。我也喜欢它可以修改以适应各种情况。尽管如果能够理解正则表达式,它无疑会更清晰和高效,就像Jan的解决方案一样。
下面的代码使用以下组合:
stringr::str_locate_all()
,它输出一个列表,每个条目的矩阵输出的第一列是模式每个出现的start
值,第二列是end
值。因此,每个嵌套矩阵的每一行都包含模式的起始和结束位置。
由于我正在使用数据框并希望使用特定的索引号,因此我发现提取与模式开头相关的数字并将其保存为数据框中的变量最容易。
purrr::map()
允许您提取特定值(在本例中为“n^th”)。我刚刚从每个矩阵中提取了第二次出现(即第二行)的开始索引(即第一列).x[,1][2]
,如我的示例所示。然后需要将此值 unlisted
并存储为 numeric
值。
stringr::str_length()
然后返回字符串的整数长度(或“字符总数”)。
在提取特定索引值之后,您需要从位置到位置提取子字符串。只需记住特殊字符需要正确 escaped
。
最后,使用 stringr::str_sub()
提取特定模式的第 n'th
次出现和字符串中的最后一个字符之间的所有内容。
text_pattern <- "-"
df <- data.table(var_name = c("kj<hdf - fæld - adsk-jf -h af",
"kj<hds - sdaf - saflaf- adf",
"asdgya - oaid - aa-s--s a-",
"k<hdfk - lkja - ljad -"))
df <- df %>%
mutate(second_dash = as.numeric(unlist
(str_locate_all(pattern = text_pattern, var_name) %>%
map(~ .x[,1][2])
)
)) %>%
mutate(New_substring = str_sub(string = var_name,
start = second_dash+2,
end = str_length(var_name)))
# var_name second_dash New_substring
# 1: kj<hdf - fæld - adsk-jf -h af 15 adsk-jf -h af
# 2: kj<hds - sdaf - saflaf- adf 15 saflaf- adf
# 3: asdgya - oaid - aa-s--s a- 15 aa-s--s a-
# 4: k<hdfk - lkja - ljad - 15 ljad -
对于您的特定情况,继续使用破折号而不是下划线,您可以使用变量n
和m
指定索引号(或出现次数)。
在下面的示例中,我从子字符串的开头添加了2并从结尾减去了2以删除空格。还应注意,索引包括所讨论的字符。因此,如果您不希望连字符“-”或下划线“_”包含在输出中,则需要从提取的索引中减去或添加至少1。这完全取决于您的具体目的。通过删除值周围的空间的“填充”,也可以更智能地实现此目标,但我只是包括修改以说明如何操作索引值。
text_pattern <- "-"
n = 2
m = n + 1
df <- data.table(var_name = c("kj<hdf - fæld - adsk-jf -h af",
"kj<hds - sdaf - saflaf- adf",
"asdgya - oaid - aa-s--s a-",
"k<hdfk - lkja - ljad -"))
df <- df %>%
mutate(n_dash = as.numeric(unlist
(str_locate_all(pattern = text_pattern, var_name) %>%
map(~ .x[,1][n])
)
)) %>%
mutate(m_dash = as.numeric(unlist
(str_locate_all(pattern = text_pattern, var_name) %>%
map(~ .x[,1][m])
)
)) %>%
mutate(New_substring = str_sub(string = var_name,
start = n_dash+2,
end = m_dash-2))
# var_name New_substring n_dash m_dash
# 1: kj<hdf - fæld - adsk-jf -h af ads 15 21
# 2: kj<hds - sdaf - saflaf- adf safla 15 23
# 3: asdgya - oaid - aa-s--s a- a 15 19
# 4: k<hdfk - lkja - ljad - ljad 15 22