根据 vectorized/unvectorized 调用,stringr 的字符串操作不起作用
String operations with stringr not working depending on vectorized/unvectorized call
我很难理解为什么我的下面的代码只有在 rowwise
与 ifelse
结合使用时才有效。或者更准确地说,我想我明白为什么它在那种情况下有效,但不明白为什么它不能简单地与 if_else
.
一起使用
我正在做的是检查某些行是否包含单词“infile”或“outfile”,以及它是否具有相对路径 ("..")。如果它有单词“infile/outfile”而不是相对路径,那么它有一个绝对路径“C:”。在这种情况下,我想用其他名称替换用户名(此处:“test”)。
有什么想法吗?
数据:
df <- structure(list(value = c("infile 'C:\Users\USER\folder\Data.sav'",
"infile '..\folder\Data.sav'", "outfile '..\folder\Data.sav'",
"test", "")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA,
-5L))
user_name <- "test"
有效代码:
df |>
rowwise() |>
mutate(value = ifelse(str_detect(value, "infile|outfile") & !str_detect(value, "\'\.\.\\"),
str_replace(value,
str_sub(value,
str_locate_all(value, "\\")[[1]][2] + 1,
str_locate_all(value, "\\")[[1]][3] - 1),
user_name),
value)) |>
ungroup()
输出:
# A tibble: 5 × 1
value
<chr>
1 "infile 'C:\Users\test\folder\Data.sav'"
2 "infile '..\folder\Data.sav'"
3 "outfile '..\folder\Data.sav'"
4 "test"
5 ""
无效的代码:
df |>
mutate(value = if_else(str_detect(value, "infile|outfile") & !str_detect(value, "\'\.\.\\"),
str_replace(value,
str_sub(value,
str_locate_all(value, "\\")[[1]][2] + 1,
str_locate_all(value, "\\")[[1]][3] - 1),
user_name),
value))
我认为这可行,但给出了警告消息:
Warning messages:
1: Problem while computing `value = if_else(...)`.
ℹ empty search patterns are not supported
2: Problem while computing `value = if_else(...)`.
ℹ empty search patterns are not supported
无效的代码:
df |>
rowwise() |>
mutate(value = if_else(str_detect(value, "infile|outfile") & !str_detect(value, "\'\.\.\\"),
str_replace(value,
str_sub(value,
str_locate_all(value, "\\")[[1]][2] + 1,
str_locate_all(value, "\\")[[1]][3] - 1),
user_name),
value)) |>
ungroup()
Error in `mutate()`:
! Problem while computing `value = if_else(...)`.
ℹ The error occurred in row 2.
Caused by error:
! Empty `pattern` not supported
这是一种方法(我对 USER
的替换非常简单;不确定是否应该更通用):
df %>%
tidyr::separate(value, into = c('Type', 'Path'), sep = ' ') %>%
dplyr::mutate(
Value = dplyr::if_else(
(Type %in% c('infile', 'outfile')) & !startsWith(Path, "'.."),
stringr::str_replace(Path, 'USER', user_name),
Path
)
)
我拆分了 value
列以便于检查。
如果您需要用变量替换用户名,您可以这样做(这里使用反向引用正则表达式):
df %>%
tidyr::separate(value, into = c('Type', 'Path'), sep = ' ') %>%
dplyr::mutate(
Value = dplyr::if_else(
(Type %in% c('infile', 'outfile')) & !startsWith(Path, "'.."),
sub('^(C:\\Users\\)([[:alnum:]]+)\\', paste0('\1', user_name, '\\'), Path),
Path
)
)
基本上,问题是 if_else()
计算每一行中的 true 和 false 输出,而 ifelse()
只计算使用它们的 true 和 false 表达式。
此外,如果您不使用 rowwise()
,则 mutate 会在每次迭代时传递 df$value
中的整个字符串集,然后 returns 开始时传递相同的索引和每一行的字符串结尾。
为了调试,我建议稍微分解一下计算:
df %>% rowwise() %>%
mutate(n=length(value), slen=str_length(value),
l1=str_locate_all(value,"\\")[[1]][2]+1,
l2=str_locate_all(value,"\\")[[1]][3]-1,
ssub=str_sub(value, l1, l2),
detect=str_detect(value, "infile|outfile")& !str_detect(value,"\'\.\.\\"),
vout=if_else(detect, ssub, user_name))
# A tibble: 5 × 8
# Rowwise:
value n slen l1 l2 ssub detect vout
<chr> <int> <int> <dbl> <dbl> <chr> <lgl> <chr>
1 "infile 'C:\Users\USER\folder\Data.sav'" 1 38 18 21 "USER" TRUE USER
2 "infile '..\folder\Data.sav'" 1 27 19 10 "" FALSE test
3 "outfile '..\folder\Data.sav'" 1 28 20 11 "" FALSE test
4 "test" 1 4 NA NA NA FALSE test
5 "" 1 0 NA NA NA FALSE test
虽然没有 rowwise()
,但 mutate 会一次性获取值列中的所有字符串,并且它会在 每一行 上找到相同的切割位置:
df %>%
mutate(n=length(value), slen=str_length(value),
l1=str_locate_all(value,"\\")[[1]][2]+1,
l2=str_locate_all(value,"\\")[[1]][3]-1,
ssub=str_sub(value, l1, l2),
detect=str_detect(value, "infile|outfile")& !str_detect(value,"\'\.\.\\"),
vout=if_else(detect, ssub, user_name))
# A tibble: 5 × 8
value n slen l1 l2 ssub detect vout
<chr> <int> <int> <dbl> <dbl> <chr> <lgl> <chr>
1 "infile 'C:\Users\USER\folder\Data.sav'" 5 38 18 21 "USER" TRUE USER
2 "infile '..\folder\Data.sav'" 5 27 18 21 "\Dat" FALSE test
3 "outfile '..\folder\Data.sav'" 5 28 18 21 "r\Da" FALSE test
4 "test" 5 4 18 21 "" FALSE test
5 "" 5 0 18 21 "" FALSE test
一旦您错误地计算了字符串子集的位置,我认为您很幸运 if_else
引发了不同的错误。
我很难理解为什么我的下面的代码只有在 rowwise
与 ifelse
结合使用时才有效。或者更准确地说,我想我明白为什么它在那种情况下有效,但不明白为什么它不能简单地与 if_else
.
我正在做的是检查某些行是否包含单词“infile”或“outfile”,以及它是否具有相对路径 ("..")。如果它有单词“infile/outfile”而不是相对路径,那么它有一个绝对路径“C:”。在这种情况下,我想用其他名称替换用户名(此处:“test”)。
有什么想法吗?
数据:
df <- structure(list(value = c("infile 'C:\Users\USER\folder\Data.sav'",
"infile '..\folder\Data.sav'", "outfile '..\folder\Data.sav'",
"test", "")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA,
-5L))
user_name <- "test"
有效代码:
df |>
rowwise() |>
mutate(value = ifelse(str_detect(value, "infile|outfile") & !str_detect(value, "\'\.\.\\"),
str_replace(value,
str_sub(value,
str_locate_all(value, "\\")[[1]][2] + 1,
str_locate_all(value, "\\")[[1]][3] - 1),
user_name),
value)) |>
ungroup()
输出:
# A tibble: 5 × 1
value
<chr>
1 "infile 'C:\Users\test\folder\Data.sav'"
2 "infile '..\folder\Data.sav'"
3 "outfile '..\folder\Data.sav'"
4 "test"
5 ""
无效的代码:
df |>
mutate(value = if_else(str_detect(value, "infile|outfile") & !str_detect(value, "\'\.\.\\"),
str_replace(value,
str_sub(value,
str_locate_all(value, "\\")[[1]][2] + 1,
str_locate_all(value, "\\")[[1]][3] - 1),
user_name),
value))
我认为这可行,但给出了警告消息:
Warning messages:
1: Problem while computing `value = if_else(...)`.
ℹ empty search patterns are not supported
2: Problem while computing `value = if_else(...)`.
ℹ empty search patterns are not supported
无效的代码:
df |>
rowwise() |>
mutate(value = if_else(str_detect(value, "infile|outfile") & !str_detect(value, "\'\.\.\\"),
str_replace(value,
str_sub(value,
str_locate_all(value, "\\")[[1]][2] + 1,
str_locate_all(value, "\\")[[1]][3] - 1),
user_name),
value)) |>
ungroup()
Error in `mutate()`:
! Problem while computing `value = if_else(...)`.
ℹ The error occurred in row 2.
Caused by error:
! Empty `pattern` not supported
这是一种方法(我对 USER
的替换非常简单;不确定是否应该更通用):
df %>%
tidyr::separate(value, into = c('Type', 'Path'), sep = ' ') %>%
dplyr::mutate(
Value = dplyr::if_else(
(Type %in% c('infile', 'outfile')) & !startsWith(Path, "'.."),
stringr::str_replace(Path, 'USER', user_name),
Path
)
)
我拆分了 value
列以便于检查。
如果您需要用变量替换用户名,您可以这样做(这里使用反向引用正则表达式):
df %>%
tidyr::separate(value, into = c('Type', 'Path'), sep = ' ') %>%
dplyr::mutate(
Value = dplyr::if_else(
(Type %in% c('infile', 'outfile')) & !startsWith(Path, "'.."),
sub('^(C:\\Users\\)([[:alnum:]]+)\\', paste0('\1', user_name, '\\'), Path),
Path
)
)
基本上,问题是 if_else()
计算每一行中的 true 和 false 输出,而 ifelse()
只计算使用它们的 true 和 false 表达式。
此外,如果您不使用 rowwise()
,则 mutate 会在每次迭代时传递 df$value
中的整个字符串集,然后 returns 开始时传递相同的索引和每一行的字符串结尾。
为了调试,我建议稍微分解一下计算:
df %>% rowwise() %>%
mutate(n=length(value), slen=str_length(value),
l1=str_locate_all(value,"\\")[[1]][2]+1,
l2=str_locate_all(value,"\\")[[1]][3]-1,
ssub=str_sub(value, l1, l2),
detect=str_detect(value, "infile|outfile")& !str_detect(value,"\'\.\.\\"),
vout=if_else(detect, ssub, user_name))
# A tibble: 5 × 8
# Rowwise:
value n slen l1 l2 ssub detect vout
<chr> <int> <int> <dbl> <dbl> <chr> <lgl> <chr>
1 "infile 'C:\Users\USER\folder\Data.sav'" 1 38 18 21 "USER" TRUE USER
2 "infile '..\folder\Data.sav'" 1 27 19 10 "" FALSE test
3 "outfile '..\folder\Data.sav'" 1 28 20 11 "" FALSE test
4 "test" 1 4 NA NA NA FALSE test
5 "" 1 0 NA NA NA FALSE test
虽然没有 rowwise()
,但 mutate 会一次性获取值列中的所有字符串,并且它会在 每一行 上找到相同的切割位置:
df %>%
mutate(n=length(value), slen=str_length(value),
l1=str_locate_all(value,"\\")[[1]][2]+1,
l2=str_locate_all(value,"\\")[[1]][3]-1,
ssub=str_sub(value, l1, l2),
detect=str_detect(value, "infile|outfile")& !str_detect(value,"\'\.\.\\"),
vout=if_else(detect, ssub, user_name))
# A tibble: 5 × 8
value n slen l1 l2 ssub detect vout
<chr> <int> <int> <dbl> <dbl> <chr> <lgl> <chr>
1 "infile 'C:\Users\USER\folder\Data.sav'" 5 38 18 21 "USER" TRUE USER
2 "infile '..\folder\Data.sav'" 5 27 18 21 "\Dat" FALSE test
3 "outfile '..\folder\Data.sav'" 5 28 18 21 "r\Da" FALSE test
4 "test" 5 4 18 21 "" FALSE test
5 "" 5 0 18 21 "" FALSE test
一旦您错误地计算了字符串子集的位置,我认为您很幸运 if_else
引发了不同的错误。