【问题标题】:Match everything but numbers regular expression匹配除数字正则表达式之外的所有内容
【发布时间】:2023-03-08 11:02:01
【问题描述】:

我想要一个正则表达式来匹配任何不正确的数学数字。下面的列表是作为正则表达式输入的示例列表:

1

1.7654

-2.5

2-

2.

m

2..3

2....233..6

2.2.8

2--5

6-4-9

所以前三个(粗体)不应该被选中,其余的应该。 这是一个与another post 相近的话题,但由于它的负面性质,它是不同的。

我正在使用 R,但我猜任何正则表达式都可以。 以下是上述帖子中的最佳镜头:

a <- c("1", "1.7654", "-2.5", "2-", "2.", "m", "2..3", "2....233..6", "2.2.8", "2--5", "6-4-9")
grep(pattern="(-?0[.]\\d+)|(-?[1-9]+\\d*([.]\\d+)?)|0$", x=a)

哪个输出:

\[1\] 1  2  3  4  5  7  8  9 10 11

【问题讨论】:

  • a[is.na(as.numeric(a))] 非常接近,除了“2”。
  • 你关心前导零吗?你想要“012”匹配还是不匹配?我猜“0.12”必须匹配。那么尾随零呢,例如“0.1200”?
  • @Spacedman 我猜这些也是数学上正确的数字。 2==0002=2.0000=0002.000
  • @docendodiscimus 的似乎最好。
  • 还有一些更奇特的数字格式,例如“1.2E05”(即 120000),但它们大多是由计算机生成的。

标签: regex r


【解决方案1】:

您可以使用以下正则表达式:

^(?:((\d+(?=[^.]+|\.{2,})).)+|(\d\.){2,}).*|[^\d]+$

查看演示https://regex101.com/r/tZ3uH0/6

请注意,您的正则表达式引擎应支持可变长度的前瞻。您需要使用 multi-line 标志,如评论中所述,您可以使用 perl=T 在 R 中进行主动前瞻。

这个正则表达式包含 2 个与 OR 连接的部分。第一部分是:

(?:((\d+(?=[^.]+|\.{2,})).)+|(\d\.){2,}).*

这将匹配一个数字组合,其后跟除点或 2 个或多个点之外的任何内容。这整个都在一个可以重复的捕获组内,而不是这个组,你可以有一个数字,后面跟着点 2 或更多时间(用于匹配一些字符串,如 2.3.4.)。

在第二部分,我们有[^\d]+,它将匹配除数字之外的任何内容。

Debuggex Demo

【讨论】:

  • 对于R 中的记录前瞻需要激活perl=T
  • @MichaelChirico 感谢您提及!
【解决方案2】:
a[grep("^-?\\d*(\\.?\\d*)$", a, invert=T)]

来自@Frank 的建议编辑。

速度测试

a <- rep(a, 1e4)
all.equal(a[is.na(as.numeric(a))], a[grep("^-?\\d+(\\.?\\d+)?$|^\\d+\\.$", a, invert=T)])
[1] TRUE

library(microbenchmark)
microbenchmark(dosc = a[is.na(as.numeric(a))],
           plafort = a[grep("^-?\\d*(\\.?\\d*)$", a, invert=T)])
# Unit: milliseconds
#     expr      min       lq     mean   median       uq      max neval
#     dosc 27.83477 28.32346 28.69970 28.51254 28.76202 31.24695   100
#  plafort 31.92118 32.14915 32.62036 32.33349 32.71107 35.12258   100

【讨论】:

  • 好吧,如果我们接受 .2 和 2. ,那么@docendodiscimus 给出的答案是最简单和最易读的。所以为了这个问题,不,他们不应该被选中。 (我想知道使用正则表达式是否比 a[is.na(as.numeric(a))] 更快)
  • "^-?\\d+(\\.?\\d+)?$" 这样您就不必将第一部分写两次。
  • 谢谢@Frank。我添加了速度测试。
  • 嗯,您的正则表达式与 docendo 的不完美平行。例如,在"-2." 上试试。当然,它在".2" 上失败,as.numeric 捕获。我想这可以用"^-?\\d*(\\.?\\d*)$" 纠正(不确定)。正如 Spacedman 所提到的,您还需要与 2E5 抗衡以镜像 as.numeric... 无论如何,对于(故意和默默地)为问题产生错误输出的已接受答案中的正则表达式似乎有点奇怪(通过允许2.)...也许@MehradMahmoudian 可以改变问题,这样才有意义...?
  • 他们在 cmets 中提到,他们希望将 2..2 视为数字。
【解决方案3】:

我认为这应该可以完成工作:

re <- "^-?[0-9]+$|^-?[0-9]+\\.[0-9]+$"
R> a[!grepl(re, a)]
#[1] "2-"          "2."          "m"           "2..3"        "2....233..6" "2.2.8"       "2--5"       
#[8] "6-4-9" 

【讨论】:

    【解决方案4】:

    解决方案here 很好。您只需添加否定案例 [-] 并反转选择!

    a <- c("1", "1.7654", "-2.5", "2-", "2.", "m", "2..3", "2....233..6", "2.2.8", "2--5", "6-4-9")
    a[grep(pattern="(^[1-9]\\d*(\\.\\d+)?$)|(^[-][1-9]\\d*(\\.\\d+)?$)",invert=TRUE, x=a)]
    
    [1] "2-"          "2."          "m"           "2..3"        "2....233..6"
    [6] "2.2.8"       "2--5"        "6-4-9" 
    

    【讨论】:

      【解决方案5】:

      试试这个:

      a[!grepl("^\\-?\\d?\\.?\\d+$", a)]
      

      【讨论】:

      • 添加一些有关此正则表达式正在做什么的信息可能会有所帮助。
      【解决方案6】:

      我喜欢 as.numeric() 的简单性。这是我的建议:

      require(stringr)
      
      a <- c("1", "1.7654", "-2.5", "2-", "2.", "m", "2..3", "2....233..6", "2.2.8", "2--5", "6-4-9")
      a
      
      a1 <- ifelse(str_sub(a, -1) == ".", "string filler", a)
      a1
      
      outvect <- is.na(as.numeric(a1))
      outvect
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-10
        • 2019-02-15
        • 2021-05-26
        • 2022-08-21
        • 2018-05-26
        • 1970-01-01
        相关资源
        最近更新 更多