如何检查以 1 开头并以 2 结尾的模式?

How to check the pattern that starts with 1 and end with 2?

提问人:doraemon 提问时间:10/4/2023 最后编辑:ThomasIsCodingdoraemon 更新时间:10/4/2023 访问量:133

问:

顺序将如下所示:

"4122222222222281222222211111212"

我想要的结果是:

"1222222222222"

"12222222"

"12"

"12"

您可以看到模式中可以有任意数量的“2”。

有没有办法在R中找到这样的模式?

r 正则表达式 字符串

评论


答:

8赞 SamR 10/4/2023 #1

关键是要用模式"12+"

正则表达式中的字符表示“与前面的字符匹配一次或多次”+

您可以使用 str_extract_all() 函数对库执行此操作:stringr

x  <- "4122222222222281222222211111212"
stringr::str_extract_all(x, "12+")
# [[1]]
# [1] "1222222222222" "12222222"      "12"            "12" 

或者,在基础 R 中,您可以使用 regmatches():

m  <- gregexpr("12+", x)
regmatches(x, m)
# [[1]]
# [1] "1222222222222" "12222222"      "12"            "12"       

这两种方法都是矢量化的,并返回一个列表。这很有用,就好像数据框列的输出将是 的列表,其中每个元素都是包含所有匹配项的字符向量。但是,如果是长度为 的向量,您可能希望将结果包装起来以返回向量。使用这种方法,您还可以:xlength(x)x1unlist()stringr

stringr::str_extract_all(x, "12+", simplify = TRUE) 
#      [,1]            [,2]       [,3] [,4]
# [1,] "1222222222222" "12222222" "12" "12"

这将返回一个字符矩阵,在本例中为一行。但是,如果您的输入具有 长度 ,这可能不是预期的结果,因为不同数量的匹配将导致带有条目的字符数组(而不是):> 1""NA

x  <- c("4122222222222281222222211111212", "135", "123")
stringr::str_extract_all(x, "12+", simplify = TRUE) 
#      [,1]            [,2]       [,3] [,4]
# [1,] "1222222222222" "12222222" "12" "12"
# [2,] ""              ""         ""   ""  
# [3,] "12"            ""         ""   ""  

有关函数和正则表达式匹配字符的详细信息,请参阅 RStudio 的有用备忘单stringrstringr

您还可以使用 ,这是一个包装器。stri_extract_all_regex(x, "12+")stringr::str_extract_all()

基准

stringr比 快得多。有一些历史基准测试表明 stringi 比 .但是,由于 ,它的许多函数都是函数的包装器,并且两个包之间的性能差异不大。以下是此正则表达式的结果,其向量范围从长度到行:regmatches()stringrv1.0.0stringrstringi11e6

enter image description here

stringi在非常短的矢量下似乎略快,但实际时间差很小(纳秒)。对于较长的向量,我们看不到太大的相对差异。有趣的是,相对于创建正则表达式的成本,简化为矩阵的性能成本并不是很高,即使数据非常大。

基准测试代码

library(stringr)
library(stringi)

results <- bench::press(
    n_strings = 10^(0:6),
    pattern = "12+",
    {
        x <- stri_rand_strings(n = n_strings, length = 20, pattern = "[1-5]")
        bench::mark(
            min_iterations = 10,
            check = FALSE,
            str_extract_all = {
                str_extract_all(x, pattern)
            },
            str_extract_all_simplify = {
                str_extract_all(x, pattern, simplify = TRUE)
            },
            stringi = {
                stri_extract_all_regex(x, pattern)
            },
            base = {
                regmatches(x, gregexpr(pattern, x))
            }
        )
    }
)

# # A tibble: 28 × 11
#    expression               n_strings pattern      min   median   `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
#    <bch:expr>                   <dbl> <chr>   <bch:tm> <bch:tm>       <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
#  1 str_extract_all                  1 12+       20.4µs   22.5µs  36001.          264B    3.60   9999     1   277.74ms
#  2 str_extract_all_simplify         1 12+       21.5µs   22.7µs  36481.          264B    3.65   9999     1   274.09ms
#  3 stringi                          1 12+        6.3µs    6.6µs 125851.            0B    0     10000     0    79.46ms
#  4 base                             1 12+       24.3µs   27.2µs  28786.        8.09KB    5.76   9998     2   347.32ms
#  5 str_extract_all                 10 12+         25µs   28.8µs  22913.          264B    2.29   9999     1    436.4ms
#  6 str_extract_all_simplify        10 12+       26.4µs   27.9µs  30625.          472B    3.06   9999     1   326.49ms
#  7 stringi                         10 12+       10.4µs   10.8µs  72548.            0B    7.26   9999     1   137.83ms
#  8 base                            10 12+       72.4µs   84.1µs   8692.       80.94KB    8.72   3988     4    458.8ms
#  9 str_extract_all                100 12+       64.6µs   68.7µs  12231.        1.09KB    2.03   6039     1   493.75ms
# 10 str_extract_all_simplify       100 12+       69.8µs  75.55µs  10732.        3.48KB    2.02   5300     1   493.87ms
# 11 stringi                        100 12+       49.7µs   51.8µs  16697.          848B    0      8335     0   499.18ms
# 12 base                           100 12+      507.7µs 677.15µs   1201.      813.95KB   13.2     548     6   456.18ms
# 13 str_extract_all               1000 12+      487.4µs 546.45µs   1526.        8.12KB    2.02    756     1   495.26ms
# 14 str_extract_all_simplify      1000 12+      538.8µs  568.5µs   1610.       47.23KB    0       805     0   500.08ms
# 15 stringi                       1000 12+      469.1µs  558.1µs   1555.        7.86KB    2.01    772     1   496.62ms
# 16 base                          1000 12+       5.01ms   5.56ms    177.        7.95MB   20.2      70     8   395.96ms
# 17 str_extract_all              10000 12+       4.94ms   5.32ms    170.       78.43KB    0        85     0   500.24ms
# 18 str_extract_all_simplify     10000 12+       5.24ms    5.8ms    167.      390.98KB    1.98     84     1   503.92ms
# 19 stringi                      10000 12+       4.86ms   5.34ms    160.       78.17KB    2.00     80     1   500.44ms
# 20 base                         10000 12+      78.43ms  88.56ms     11.0      79.46MB   12.1      10    11   905.52ms
# 21 str_extract_all             100000 12+      53.45ms  57.39ms     16.8     781.55KB    1.68     10     1   595.49ms
# 22 str_extract_all_simplify    100000 12+      59.91ms   66.8ms     13.6       4.58MB    1.36     10     1   734.33ms
# 23 stringi                     100000 12+      52.52ms  53.85ms     18.3      781.3KB    0        10     0    545.4ms
# 24 base                        100000 12+      808.5ms 992.12ms      0.956    794.6MB   14.6      10   153     10.46s
# 25 str_extract_all            1000000 12+     533.78ms 627.43ms      1.16      7.63MB    0.116    10     1       8.6s
# 26 str_extract_all_simplify   1000000 12+     637.49ms 709.24ms      1.36     53.41MB    0.136    10     1      7.34s
# 27 stringi                    1000000 12+     537.19ms 600.58ms      1.64      7.63MB    0.164    10     1      6.09s
# 28 base                       1000000 12+          10s   11.74s      0.0857    7.76GB    3.03     10   353      1.95m


# Plot
library(ggplot2)
p  <- autoplot(results) +
    theme_bw() +
    facet_wrap(vars(n_strings), ncol = 1, labeller = "label_both")