5

我正在尝试构建一个能够解析句子并返回数字的 javascript 函数。

这是我为下面的测试用例设置的jsFiddle -

  1. '我有 1 磅' -> 1
  2. “我有 3.50 英镑要花”-> 3.50
  3. “我有 23.00 磅”-> 23
  4. “27.33 英镑”-> 27.33
  5. “$4345.85”-> 4345.85
  6. '3.00' -> 3
  7. '7.0' -> 7
  8. “应该有 2.0。” -> 2
  9. “应该有 15.20。” -> 15.20
  10. '3.15' -> 3.15
  11. “我只有5个,不是很好。” -> 5
  12. “34.23”-> 34.23
  13. 'sdfg545.14sdfg' -> 545.14
  14. “昨天我花了 235468.13 英镑。今天我想少花钱。-> 235468.13
  15. “昨天我花了 340 英镑。” -> 340
  16. “我今天花了 14.52 英镑,明天花了 17.30 英镑”-> 14.52
  17. “我有 0 棵树,明天 11.33 英镑”-> 0

16&17 表示它应该找到第一个数字。我知道某些测试用例可能很难,但我欢迎任何能让我得到合理覆盖的东西。

这是我用于我的功能的格式

function parseSentenceForNumber(sentence){

    return number; //The number from the string
}

我想我自己可以完成 60-80% 的工作,但我希望正则表达式可能是这里最好的解决方案,而我从来都不擅长它们。希望我有足够的测试用例,但可以随意添加我可能错过的任何测试用例。

非常感谢您的帮助。

**更新**

大量有效的答案,我需要花一些时间更详细地研究它们。Mike Samuel 提到了逗号和 .5,这导致我添加了另外几个测试用例

18.'我有 1,000 英镑' -> 1000 19.'.5' -> 0.5

并且 jsalonen 提到为没有数字添加测试用例

20.'这句话不包含数字' -> null

这是使用 jsalonen 解决方案的更新小提琴,如果没有我对规范的更改,我会 100% 在那里,而我的更改是 95%。任何人都可以用逗号提供数字 18 的解决方案吗?

**更新**

我添加了一条语句来去除 jsalonen 函数中的逗号,我达到了 100%。

这是最终的功能

function parseSentenceForNumber(sentence){
    var matches = sentence.replace(/,/g, '').match(/(\+|-)?((\d+(\.\d+)?)|(\.\d+))/);
    return matches && matches[0] || null;
}

最后的小提琴

非常感谢您的帮助,并且在此过程中我已经提高了我的正则表达式知识。谢谢

4

6 回答 6

2

正则表达式:

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

应该这样做。

  • \d+匹配一个数字序列。
  • .\d+ 匹配小数点后跟数字。
  • (?:...)?使该组可选

这不处理分数全为零的特殊情况,并且您不希望分数包含在结果中,这对于正则表达式很困难(我不确定它是否可以完成,尽管我'我愿意被证明是错误的)。在将数字与其中的小数匹配后,应该更容易处理。

匹配字符串中的数字后,使用parseFloat()将其转换为数字,并toFixed(2)获得 2 位小数。

于 2013-07-26T15:58:44.080 回答
2

与任意位数的所有负数和正数匹配的答案:

function parseSentenceForNumber(sentence){
    var matches = sentence.match(/(\+|-)?((\d+(\.\d+)?)|(\.\d+))/);
    return matches && matches[0] || null;
}

也可以考虑添加负面测试用例,例如测试字符串没有数字时会发生什么:

test("Test parseSentenceForNumber('This sentence contains no numbers')", function() {
  equal( parseSentenceForNumber('This sentence contains no numbers'), null );
});

完整的小提琴:http: //jsfiddle.net/cvw8g/6/

于 2013-07-26T16:01:21.930 回答
2

计算机可读形式的数字的一般形式是:

/[+\-]?((?:[1-9]\d*|0)(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?/

基于语法

number            := optional_sign (integer optional_fraction | fraction) optional_exponent;
optional_sign     := '+' | '0' | ε;
integer           := decimal_digit optional_integer;
optional_integer  := integer | ε;
optional_fraction := '.' optional_integer | ε;
fraction          := '.' integer;
optional_exponent := ('e' | 'E') optional_sign integer;

所以你可以做

function parseSentenceForNumber(sentence){
  var match = sentence.match(
      /[+\-]?((?:[1-9]\d*|0)(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?/);
  return match ? +match[0] : null; //The number from the string
}

但这并不能说明

  1. 使用除 '.' 以外的分数分隔符的语言环境 如“π 是 3,14159...”
  2. 逗号分隔数字组,如 1,000,000
  3. 分数
  4. 百分比
  5. 自然语言描述,如“一打”或“1500 万英镑”

要处理这些情况,您可能会搜索“实体提取”,因为这是试图在非结构化文本中查找指定结构化数据的短语的总体字段。

于 2013-07-26T16:06:46.133 回答
1

另一种可能的正则表达式:

/\d+\.?\d{0,2}/

这表示:

  • \d: 一位或多位数字
  • \.?: 零个或一个周期
  • d{0,2}最多 2 位数

http://jsfiddle.net/cvw8g/7/

于 2013-07-26T16:02:26.200 回答
1

没有正则表达式,也使用 parse (如果没有找到数字,将返回 NaN)。
查找字符串中的第一个数字,然后尝试从该点解析它。

通过所有测试,并返回一个数字,而不是字符串,因此您可以立即将其用于比较或算术。

function parseSentenceForNumber(str) {
    //tacked on to support the new "1,000" -> 1000 case
    str = str.replace(',', '');

    var index;
    //find the first digit
    for (index = 0; index < str.length; ++index) {
        if (str.charAt(index) >= '0' && str.charAt(index) <= '9')
            break;
    }

    //checking for negative or decimal point (for '.5')
    if (index > 0 && (
        str.charAt(index - 1) == '-' ||
        str.charAt(index - 1) == '.'
    ))
        //go back one character
        --index;

    //get the rest of the string, accepted by native parseFloat
    return parseFloat(str.substring(index));
}
于 2013-07-26T16:06:12.937 回答
1

通过所有测试,我认为它更具可读性:

function parseSentenceForNumber(sentence){
    return parseFloat(sentence.replace(/,(?=\d)/g,"").match(/-?\.?\d.*/g));
}

...几乎所有测试:当句子中没有数字时,它返回“NaN”而不是“null”。但我认为“NaN”比简单的“null”信息量更大。

这是 jsFiddle:http: //jsfiddle.net/55AXf/

于 2013-07-26T16:35:38.307 回答