用于处理点和逗号作为有效小数分隔符的正则表达式/ perl代码

kno*_*orv 0 regex perl

我正在尝试创建一种方法,在我不知道最终用户正在使用的这两种互斥方式编写数字的方式中,提供"尽力而为"的十进制输入解析:

  • "" 作为千位分隔符和","作为小数分隔符
  • ","作为千位分隔符和"." 作为小数分隔符

该方法如parse_decimal(..)下面的代码中那样实现.此外,我已经定义了20个测试用例,显示了该方法的启发式方法应该如何工作.

虽然下面的代码通过了测试,但它非常可怕且难以理解.我确信有一种更紧凑和可读的方法来实现该方法.可能包括更聪明地使用正则表达式.

我的问题很简单:鉴于下面的代码和测试用例,你如何改进parse_decimal(...)以使其在传递测试时更加紧凑和可读?

澄清:

  • 澄清#1:正如评论中所指出的那样,案例^\d{1,3}[\.,]\d{3}$含糊不清,因为人们不能逻辑地确定哪个字符用作千位分隔符,哪个字符用作小数分隔符.在不明确的情况下,我们将简单地假设使用美式小数:","作为千位分隔符和"." 作为小数分隔符.
  • 澄清#2:如果您认为任何测试用例都是错误的,请说明应该更改哪些测试以及如何更改.

有问题的代码包括测试用例:

#!/usr/bin/perl -wT

use strict;
use warnings;
use Test::More tests => 20;

ok(&parse_decimal("1,234,567") == 1234567);
ok(&parse_decimal("1,234567") == 1.234567);
ok(&parse_decimal("1.234.567") == 1234567);
ok(&parse_decimal("1.234567") == 1.234567);
ok(&parse_decimal("12,345") == 12345);
ok(&parse_decimal("12,345,678") == 12345678);
ok(&parse_decimal("12,345.67") == 12345.67);
ok(&parse_decimal("12,34567") == 12.34567);
ok(&parse_decimal("12.34") == 12.34);
ok(&parse_decimal("12.345") == 12345);
ok(&parse_decimal("12.345,67") == 12345.67);
ok(&parse_decimal("12.345.678") == 12345678);
ok(&parse_decimal("12.34567") == 12.34567);
ok(&parse_decimal("123,4567") == 123.4567);
ok(&parse_decimal("123.4567") == 123.4567);
ok(&parse_decimal("1234,567") == 1234.567);
ok(&parse_decimal("1234.567") == 1234.567);
ok(&parse_decimal("12345") == 12345);
ok(&parse_decimal("12345,67") == 12345.67);
ok(&parse_decimal("1234567") == 1234567);

sub parse_decimal($) {
    my $input = shift;
    $input =~ s/[^\d,\.]//g;
    if ($input !~ /[,\.]/) {
        return &parse_with_separators($input, '.', ',');
    } elsif ($input =~ /\d,\d+\.\d/) {
        return &parse_with_separators($input, '.', ',');
    } elsif ($input =~ /\d\.\d+,\d/) {
        return &parse_with_separators($input, ',', '.');
    } elsif ($input =~ /\d\.\d+\.\d/) {
        return &parse_with_separators($input, ',', '.');
    } elsif ($input =~ /\d,\d+,\d/) {
        return &parse_with_separators($input, '.', ',');
    } elsif ($input =~ /\d{4},\d/) {
        return &parse_with_separators($input, ',', '.');
    } elsif ($input =~ /\d{4}\.\d/) {
        return &parse_with_separators($input, '.', ',');
    } elsif ($input =~ /\d,\d{3}$/) {
        return &parse_with_separators($input, '.', ',');
    } elsif ($input =~ /\d\.\d{3}$/) {
        return &parse_with_separators($input, ',', '.');
    } elsif ($input =~ /\d,\d/) {
        return &parse_with_separators($input, ',', '.');
    } elsif ($input =~ /\d\.\d/) {
        return &parse_with_separators($input, '.', ',');
    } else {
        return &parse_with_separators($input, '.', ',');
    }
}

sub parse_with_separators($$$) {
    my $input = shift;
    my $decimal_separator = shift;
    my $thousand_separator = shift;
    my $output = $input;
    $output =~ s/\Q${thousand_separator}\E//g;
    $output =~ s/\Q${decimal_separator}\E/./g;
    return $output;
}
Run Code Online (Sandbox Code Playgroud)

jro*_*way 5

这就像自动猜测输入的字符编码的程序 - 它有时可能会起作用,但总的来说是一种非常糟糕的策略,导致错误和混淆的非确定性行为.

例如,如果您看到"123,456",则表示您没有足够的信息来猜测这意味着什么.

所以我会谨慎对待这个问题,并且永远不要将这种技术用于任何重要的事情.

  • 在这些类型的任务中,有时诀窍是尽可能多地转换数据并标记奇怪的情况以供人类决策.如果数据总是干净的,那么生活将是巨大的,但我们知道这不是现实.我认为"非确定性"有点苛刻.它可能有意外的转换,但相同的输入应该提供相同的输出,即使它是不正确的. (3认同)