如何使用正则表达式提取 R 中字符串的不匹配部分?
How can I extract the unmatched portion of a string in R with regular expressions?
我有一个非常混乱的字符串向量。这是一个例子:
library(tidyverse)
library(stringr)
strings <- tibble(
name = c("lorem 11:07:59 86136-1-sed",
"ipsum 14:35:57 S VARNAME-ut",
"dolor 10:37:53 1513 -2-perspiciatis",
"sit 10:48:25",
"amet 13:52:1365293-2-unde",
"consectetur 11:53:1 16018-2-omnis",
"adipiscing 11:19 17237-2-iste"
)
)
strings_out <- strings %>%
mutate(heads = str_extract(name, "^.*?\s\d{1,2}:\d{1,2}:\d{1,2}")) %>%
mutate(ends = str_replace(name, "^.*?\s\d{1,2}:\d{1,2}:\d{1,2}", ""))
strings_out[,2:3]
#> # A tibble: 7 x 2
#> heads ends
#> <chr> <chr>
#> 1 lorem 11:07:59 86136-1-sed
#> 2 ipsum 14:35:57 S VARNAME-ut
#> 3 dolor 10:37:53 1513 -2-perspiciatis
#> 4 sit 10:48:25
#> 5 amet 13:52:13 65293-2-unde
#> 6 consectetur 11:53:1 16018-2-omnis
#> 7 <NA> adipiscing 11:19 17237-2-iste
所以这里我有一些字符串,其中包含一些文本,后跟可能输入正确或可能不正确的时间,然后是更多文本。我只想在时间之后提取字符串的结尾,但是它们没有任何模式似乎与使用 str_extract
的潜在正则表达式很好地对应。我可以轻松匹配字符串的前半部分,如 heads
所示。但是,我发现提取后半部分的唯一方法是使用 str_replace
和空字符串,如 ends
.
所示
我试图将我注意到的所有常见错误包括在此列表中:没有关于时间后的连字符、空格或字符串内容的模式,不能保证 space 时间和所需的结束一半之间字符串,乘以缺失数字甚至冒号。
我想做的是能够使用 str_extract
得到接近我用 str_replace
得到的东西。关键区别在于,对于此正则表达式仍然不起作用的错误,str_extract
给我一个易于过滤和手动修复的 NA
,但 str_replace
只是复制整个第 7 行中显示的字符串。
我怀疑我可以用一些更 hacky 的方法来做到这一点,比如获取所有 NA
并手动修复 Excel 之类的,但令我惊讶的是我不知道如何return 尽管搜索并尝试了包括 (^)
和 [^]
在内的不同正则表达式,但通常是字符串的不匹配部分。有什么想法吗?
一般来说,您可能想要查看 lookarounds,但您的数据可能需要更多结构才能发挥作用。
这是我在意识到时间后并不总是有 space 之前写的一个简单示例:
library(tidyverse)
library(stringr)
strings <- tibble(
name = c("lorem 11:07:59 86136-1-sed",
"ipsum 14:35:57 S VARNAME-ut",
"dolor 10:37:53 1513 -2-perspiciatis",
"sit 10:48:25",
"amet 13:52:1365293-2-unde",
"consectetur 11:53:1 16018-2-omnis",
"adipiscing 11:19 17237-2-iste"
)
)
strings_out <- strings %>%
mutate(heads = str_extract(name, "^.*?\s\d{1,2}:\d{1,2}:\d{1,2}"),
ends = str_extract(name, "(?<=:\d{1,2} )[\s\S]+$"))
strings_out[c(1,3)]
#> # A tibble: 7 x 2
#> name ends
#> <chr> <chr>
#> 1 lorem 11:07:59 86136-1-sed 86136-1-sed
#> 2 ipsum 14:35:57 S VARNAME-ut S VARNAME-ut
#> 3 dolor 10:37:53 1513 -2-perspiciatis 1513 -2-perspiciatis
#> 4 sit 10:48:25 <NA>
#> 5 amet 13:52:1365293-2-unde <NA>
#> 6 consectetur 11:53:1 16018-2-omnis 16018-2-omnis
#> 7 adipiscing 11:19 17237-2-iste 17237-2-iste
这里的问题是像第 5 行这样的行。没有更多的结构,我们无法知道时间是 13:52:13
还是 13:52:1
,因为两者都是其他字符串中存在的选项。判断哪个正确不是正则表达式可以解决的问题
你也可以试试这个:
library(tidyverse)
library(stringr)
regex = "^\w+\s\d{2}:\d{2}:*\d{0,2}"
strings %>%
mutate(head = str_extract(name, regex),
end = str_replace(name, paste0(regex, "\s?"), ""),
end = str_replace(end, "^\s*$", NA_character_))
结果:
# A tibble: 7 x 3
name head end
<chr> <chr> <chr>
1 lorem 11:07:59 86136-1-sed lorem 11:07:59 86136-1-sed
2 ipsum 14:35:57 S VARNAME-ut ipsum 14:35:57 S VARNAME-ut
3 dolor 10:37:53 1513 -2-perspiciatis dolor 10:37:53 1513 -2-perspiciatis
4 sit 10:48:25 sit 10:48:25 <NA>
5 amet 13:52:1365293-2-unde amet 13:52:13 65293-2-unde
6 consectetur 11:53:1 16018-2-omnis consectetur 11:53:1 16018-2-omnis
7 adipiscing 11:19 17237-2-iste adipiscing 11:19 17237-2-iste
注:
我的解决方案适用于第 5 行,但您必须决定在这种情况下是要提取 13:52:13
还是 13:52:1
。这两种情况都可以通过对正则表达式进行简单修改来完成,但正如@Zach 所述,没有自动方法。
您只需多加一行即可:
strings["rx"] <- str_match(strings$name, "\d*:\d*(?::\d+)?(.*)")[,2]
strings
产生
# A tibble: 7 x 2
name rx
<chr> <chr>
1 lorem 11:07:59 86136-1-sed 86136-1-sed
2 ipsum 14:35:57 S VARNAME-ut S VARNAME-ut
3 dolor 10:37:53 1513 -2-perspiciatis 1513 -2-perspiciatis
4 sit 10:48:25
5 amet 13:52:1365293-2-unde -2-unde
6 consectetur 11:53:1 16018-2-omnis 16018-2-omnis
7 adipiscing 11:19 17237-2-iste 17237-2-iste
我有一个非常混乱的字符串向量。这是一个例子:
library(tidyverse)
library(stringr)
strings <- tibble(
name = c("lorem 11:07:59 86136-1-sed",
"ipsum 14:35:57 S VARNAME-ut",
"dolor 10:37:53 1513 -2-perspiciatis",
"sit 10:48:25",
"amet 13:52:1365293-2-unde",
"consectetur 11:53:1 16018-2-omnis",
"adipiscing 11:19 17237-2-iste"
)
)
strings_out <- strings %>%
mutate(heads = str_extract(name, "^.*?\s\d{1,2}:\d{1,2}:\d{1,2}")) %>%
mutate(ends = str_replace(name, "^.*?\s\d{1,2}:\d{1,2}:\d{1,2}", ""))
strings_out[,2:3]
#> # A tibble: 7 x 2
#> heads ends
#> <chr> <chr>
#> 1 lorem 11:07:59 86136-1-sed
#> 2 ipsum 14:35:57 S VARNAME-ut
#> 3 dolor 10:37:53 1513 -2-perspiciatis
#> 4 sit 10:48:25
#> 5 amet 13:52:13 65293-2-unde
#> 6 consectetur 11:53:1 16018-2-omnis
#> 7 <NA> adipiscing 11:19 17237-2-iste
所以这里我有一些字符串,其中包含一些文本,后跟可能输入正确或可能不正确的时间,然后是更多文本。我只想在时间之后提取字符串的结尾,但是它们没有任何模式似乎与使用 str_extract
的潜在正则表达式很好地对应。我可以轻松匹配字符串的前半部分,如 heads
所示。但是,我发现提取后半部分的唯一方法是使用 str_replace
和空字符串,如 ends
.
我试图将我注意到的所有常见错误包括在此列表中:没有关于时间后的连字符、空格或字符串内容的模式,不能保证 space 时间和所需的结束一半之间字符串,乘以缺失数字甚至冒号。
我想做的是能够使用 str_extract
得到接近我用 str_replace
得到的东西。关键区别在于,对于此正则表达式仍然不起作用的错误,str_extract
给我一个易于过滤和手动修复的 NA
,但 str_replace
只是复制整个第 7 行中显示的字符串。
我怀疑我可以用一些更 hacky 的方法来做到这一点,比如获取所有 NA
并手动修复 Excel 之类的,但令我惊讶的是我不知道如何return 尽管搜索并尝试了包括 (^)
和 [^]
在内的不同正则表达式,但通常是字符串的不匹配部分。有什么想法吗?
一般来说,您可能想要查看 lookarounds,但您的数据可能需要更多结构才能发挥作用。
这是我在意识到时间后并不总是有 space 之前写的一个简单示例:
library(tidyverse)
library(stringr)
strings <- tibble(
name = c("lorem 11:07:59 86136-1-sed",
"ipsum 14:35:57 S VARNAME-ut",
"dolor 10:37:53 1513 -2-perspiciatis",
"sit 10:48:25",
"amet 13:52:1365293-2-unde",
"consectetur 11:53:1 16018-2-omnis",
"adipiscing 11:19 17237-2-iste"
)
)
strings_out <- strings %>%
mutate(heads = str_extract(name, "^.*?\s\d{1,2}:\d{1,2}:\d{1,2}"),
ends = str_extract(name, "(?<=:\d{1,2} )[\s\S]+$"))
strings_out[c(1,3)]
#> # A tibble: 7 x 2
#> name ends
#> <chr> <chr>
#> 1 lorem 11:07:59 86136-1-sed 86136-1-sed
#> 2 ipsum 14:35:57 S VARNAME-ut S VARNAME-ut
#> 3 dolor 10:37:53 1513 -2-perspiciatis 1513 -2-perspiciatis
#> 4 sit 10:48:25 <NA>
#> 5 amet 13:52:1365293-2-unde <NA>
#> 6 consectetur 11:53:1 16018-2-omnis 16018-2-omnis
#> 7 adipiscing 11:19 17237-2-iste 17237-2-iste
这里的问题是像第 5 行这样的行。没有更多的结构,我们无法知道时间是 13:52:13
还是 13:52:1
,因为两者都是其他字符串中存在的选项。判断哪个正确不是正则表达式可以解决的问题
你也可以试试这个:
library(tidyverse)
library(stringr)
regex = "^\w+\s\d{2}:\d{2}:*\d{0,2}"
strings %>%
mutate(head = str_extract(name, regex),
end = str_replace(name, paste0(regex, "\s?"), ""),
end = str_replace(end, "^\s*$", NA_character_))
结果:
# A tibble: 7 x 3
name head end
<chr> <chr> <chr>
1 lorem 11:07:59 86136-1-sed lorem 11:07:59 86136-1-sed
2 ipsum 14:35:57 S VARNAME-ut ipsum 14:35:57 S VARNAME-ut
3 dolor 10:37:53 1513 -2-perspiciatis dolor 10:37:53 1513 -2-perspiciatis
4 sit 10:48:25 sit 10:48:25 <NA>
5 amet 13:52:1365293-2-unde amet 13:52:13 65293-2-unde
6 consectetur 11:53:1 16018-2-omnis consectetur 11:53:1 16018-2-omnis
7 adipiscing 11:19 17237-2-iste adipiscing 11:19 17237-2-iste
注:
我的解决方案适用于第 5 行,但您必须决定在这种情况下是要提取 13:52:13
还是 13:52:1
。这两种情况都可以通过对正则表达式进行简单修改来完成,但正如@Zach 所述,没有自动方法。
您只需多加一行即可:
strings["rx"] <- str_match(strings$name, "\d*:\d*(?::\d+)?(.*)")[,2]
strings
产生
# A tibble: 7 x 2
name rx
<chr> <chr>
1 lorem 11:07:59 86136-1-sed 86136-1-sed
2 ipsum 14:35:57 S VARNAME-ut S VARNAME-ut
3 dolor 10:37:53 1513 -2-perspiciatis 1513 -2-perspiciatis
4 sit 10:48:25
5 amet 13:52:1365293-2-unde -2-unde
6 consectetur 11:53:1 16018-2-omnis 16018-2-omnis
7 adipiscing 11:19 17237-2-iste 17237-2-iste