【问题标题】:Ruby regex return array of numbers onlyRuby 正则表达式仅返回数字数组
【发布时间】:2014-07-17 16:14:47
【问题描述】:

我有以下字符串:

1: "AMETHYST 9.5x10.5 OVAL CHECKERBOARD AAA"

2: "AMETHYST 9x10 OVAL CHECKERBOARD AAA"

3: "AMETHYST 9-10 OVAL CHECKERBOARD AAA"

4: "AMETHYST 9.5-10.5 OVAL CHECKERBOARD AAA"

5: "AMETHYST 9.5 OVAL CHECKERBOARD AAA"

6: "AMETHYST 9 OVAL CHECKERBOARD AAA"

我希望我的正则表达式返回一个整数或浮点数的数组,例如采用第一​​种情况:

[
  [0] "9.5"
  [1] "10.5"
]

在对 Rubular 进行了多次尝试后,我想出了:

/\d+[.]\d+?/

这为我提供了在 Rubular.com 上查看时所需的大部分匹配结果。但是在情况 2、3、6 中,它不会拾取 - 或 x 字符前面的整数,或者当 int 像情况 6 一样单独时。

我错过了什么?

谢谢!

【问题讨论】:

  • 数据中有前缀“1:, 2:, 3:”吗?还是只是为了标记线条?
  • 大家注意。问题是:“我错过了什么?”到目前为止,只有 Nishu 和我的答案回答了这个问题。
  • 这不是危险,你可以用任何你喜欢的方式来表达答案。用正则表达式或其他替代方法解决他的问题的工作示例仍然是有用的答案。除了“我错过了什么?”更多的是一种表达,而不是具体的要求。
  • 只有 OP 才能确定回答问题的内容。

标签: ruby arrays regex


【解决方案1】:

应该这样做:

def doit(str)
  str.scan(/\d+\.?\d*/)
end

doit "AMETHYST 9.5x10.5 OVAL CHECKERBOARD AAA" #=> ["9.5", "10.5"]
doit "AMETHYST 9x10 OVAL CHECKERBOARD AAA"     #=> ["9", "10"]
doit "AMETHYST 9-10 OVAL CHECKERBOARD AAA"     #=> ["9", "10"]
doit "AMETHYST 9.5-10.5 OVAL CHECKERBOARD AAA" #=> ["9.5", "10.5"]
doit "AMETHYST 9.5 OVAL CHECKERBOARD AAA"      #=> ["9.5"]
doit "AMETHYST 9 OVAL CHECKERBOARD AAA"        #=> ["9"]

【讨论】:

  • #scan -- 就是这样。没有争论。
  • @Arup,实际上,它确实需要一个参数。 :-)
【解决方案2】:

您缺少将句点字符设为可选。这可以通过使用量词? 来完成。

顺便说一句,尚不清楚为什么需要使小数位不贪心。您没有解释说您只需要小数点以下的一位数。此外,在这种情况下,与\d+? 中的量词+ 一起使用是没有意义的;它与\d 的效果相同。

要使其正常工作,您可以使用这样的正则表达式:

/\d+\.?\d*/

/\d+(?:\.\d+)?/

【讨论】:

  • 假设 OP 想要提取所有以一位或多位数字开头的字符串,可能后跟最多一个句点,如果句点存在,它必须后跟一个或多个附加数字。你会使用什么正则表达式?
  • @CarySwoveland 我的第二个正则表达式会这样做。
  • 您的第二个正则表达式为“AMETHYST 9.5x10.OVAL”返回 ["9.5", "10"]。我的意思是正则表达式将为该字符串返回["9.5"];即,忽略10.,因为10. 后面没有数字。只是好奇。
  • @CarySwoveland 我明白了。 /\d+\.\d+|(?<!\.)\d+(?!\.)/ 呢?
【解决方案3】:

正则表达式中缺少两件事。

首先:使用 ? 将点字符设为可选字符跟随它。 第二:通过添加*将点后面的值设为可选和动态长度

\d+[.]?\d*

【讨论】:

  • 使用[.] 是逃避. 的漫长道路。相反,请使用\.
  • 同意。在问题本身中继续约定。
【解决方案4】:

假设您的示例输入是准确的,我会使用 scan,因为这就是它的用途,并稍微调整结果以仅返回您想要的值:

strings = [
  '1: "AMETHYST 9.5x10.5 OVAL CHECKERBOARD AAA"',
  '2: "AMETHYST 9x10 OVAL CHECKERBOARD AAA"',
  '3: "AMETHYST 9-10 OVAL CHECKERBOARD AAA"',
  '4: "AMETHYST 9.5-10.5 OVAL CHECKERBOARD AAA"',
  '5: "AMETHYST 9.5 OVAL CHECKERBOARD AAA"',
  '6: "AMETHYST 9 OVAL CHECKERBOARD AAA"',
]

strings.map{ |s| s.scan(/\d+[.\d]*/)[1..-1] }
# => [["9.5", "10.5"],
#     ["9", "10"],
#     ["9", "10"],
#     ["9.5", "10.5"],
#     ["9.5"],
#     ["9"]]

/\d+[.\d]*/ 表示“查找一个或多个数字,可选地后跟任意数量的 '.' 和数字。这将与前导 1: 匹配,但对数组进行切片会去除这些数字。如果数字存在,例如 1.0.0.0该模式将返回1.0.0.0,但这对于这种输出来说是一个非常荒谬的值,所以我认为该模式是相当安全的。

如果示例输入不准确,并且行号并不真正存在,那么它会变得更简单:

strings = [
  '"AMETHYST 9.5x10.5 OVAL CHECKERBOARD AAA"',
  '"AMETHYST 9x10 OVAL CHECKERBOARD AAA"',
  '"AMETHYST 9-10 OVAL CHECKERBOARD AAA"',
  '"AMETHYST 9.5-10.5 OVAL CHECKERBOARD AAA"',
  '"AMETHYST 9.5 OVAL CHECKERBOARD AAA"',
  '"AMETHYST 9 OVAL CHECKERBOARD AAA"',
]

strings.map{ |s| s.scan(/\d+[.\d]*/) }
# => [["9.5", "10.5"],
#     ["9", "10"],
#     ["9", "10"],
#     ["9.5", "10.5"],
#     ["9.5"],
#     ["9"]]

【讨论】:

    【解决方案5】:

    对于您提供的示例,这适用于 Rubular:

    \d+(?:[.]\d+)?
    

    只需在最后一部分周围放置一个非捕获组并放置最后一个?在外面使它成为 0 或 1 而不是惰性量词。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-14
      • 2014-06-01
      • 2020-08-02
      • 1970-01-01
      • 2021-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多