匹配除数字以外的所有内容的正则表达式

5
我希望有一个正则表达式,能够匹配任何不正确的数学数字。以下列表是正则表达式的输入示例:
1

1.7654

-2.5

2-

2.

m

2..3

2....233..6

2.2.8

2--5

6-4-9

所以前三个(用粗体标记的)不应被选择,其余的应该被选择。 这与另一篇帖子非常接近,但由于它的负面性质,它是不同的。 我正在使用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

7
a[is.na(as.numeric(a))]相当接近,除了其中的“2.”。 - talat
1
你在意前导零吗?你想让“012”匹配还是不匹配?我猜“0.12”必须匹配。那么像“0.1200”这样的尾随零呢? - Spacedman
@docendodiscimus 的看起来最好。 - MichaelChirico
suppressWarnings(a[is.na(as.numeric(a))]),灵感来自于这里 - MichaelChirico
2
还有一些稍微有些奇特的数字格式,比如“1.2E05”(表示120000),但它们大多数是由计算机生成的。 - Spacedman
显示剩余2条评论
6个回答

4
您可以使用以下正则表达式:
^(?:((\d+(?=[^.]+|\.{2,})).)+|(\d\.){2,}).*|[^\d]+$

请查看演示:https://regex101.com/r/tZ3uH0/6 请注意,您的正则表达式引擎应支持具有可变长度的前瞻,并且您需要使用“multi-line”标志。如评论所述,您可以使用“perl=T”在R中激活前瞻。
此正则表达式包含两个部分,已通过OR连接起来。第一部分是:
(?:((\d+(?=[^.]+|\.{2,})).)+|(\d\.){2,}).*

这段代码将匹配由数字组成的组合,其后跟除点以外的任何字符或2个或更多个点。整个代码块位于可重复捕获组中,而在此组之后,您可以有一个数字,其后跟2个或更多个点(用于匹配一些字符串,例如2.3.4.)。

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

正则表达式可视化

Debuggex演示


1
记录一下,在 R 中使用前瞻需要激活 perl=T - MichaelChirico
@MichaelChirico 谢谢提及! - Mazdak

2
我认为这应该可以完成任务:
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" 

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))]更快) - Mehrad Mahmoudian
1
或者使用 "^-?\d+(\.?\d+)?$",这样您就不必重复编写第一部分。 - Frank
1
谢谢@Frank。我添加了一个速度测试。 - Pierre L
嗯,你的正则表达式与docendo的不完全相同。例如,在"-2."上尝试它。当然,它在.2上失败了,而as.numeric却可以捕获它。我猜这可以通过"^-?\\d*(\\.?\\d*)$"(不确定)来纠正。正如Spacedman所提到的,您还需要处理2E5以反映as.numeric...无论如何,对于接受答案中的正则表达式来说,似乎有点奇怪(故意和悄悄地)为问题产生错误的输出(允许2.)...也许@MehradMahmoudian可以修改问题,使其有意义...? - Frank
1
他们在评论中提到希望将2..2视为数字。 - Pierre L

0

这个方案很不错。你只需要添加负面情况[-]并反转选择就可以了!

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" 

0

试试这个:

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

2
可能添加一些关于这个正则表达式正在做什么的信息会很有帮助。 - Justin Wood

0

我喜欢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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接