Isso é um número?

17

Prelúdio:

Eu queria treinar na criação de casos de teste, então vou experimentá-los em algo fácil.

Desafio:

Pegue qualquer entrada (string) (dentro do intervalo ASCII visível) e deduza se é um número e produza algo que possa ser usado para avaliar.

Regras:

  • Um número conterá apenas os caracteres -0123456789,.
  • As respostas são necessárias apenas para reconhecer números entre -1000000000 e 1000000000 (exclusivo), mas podem reconhecer números arbitrariamente grandes.
  • Você pode escrever um programa completo ou uma função.
  • Se um número, retorne qualquer coisa que possa ser usada para discerni-lo e documente a saída na descrição (ex. My program outputs T if a number, F if not.).
  • Entrada terá qualquer quantidade de caracteres dentro do intervalo ASCII ou vazio (se vazio retornar o que você produziria se não fosse um número).
  • Os números podem incluir um ponto decimal (ex. 3.14). Se o fizerem, eles devem ter pelo menos um dígito antes do ponto decimal e pelo menos um depois dele.
  • Os números podem ter zeros à esquerda ou à direita (ex. 000001.00000).
  • A parte inteira de um número pode ser dividida para facilitar a leitura em pedaços de três dígitos com vírgulas (ex. 1,000.23456). Neste caso, devem ser dividida a cada três dígitos da direita para a esquerda (ex. 1,234,567, 10,000.202, 123,234.00, 0,123.293).
  • Os números negativos são indicados por um princípio -(ex. -1.23). Uma +indicação para indicar um número positivo não é permitida e deve resultar na saída falsa.
  • As exceções NÃO são contadas como saída válida e discernível (exceto quando elas podem transmitir saídas para o fluxo de saída padrão (por exemplo, Exception on line N [...]podem ser inseridas como saída para um número / não-número se a string for colocada no fluxo de saída padrão).

Casos de teste:

(assumindo a My program outputs T if a number, F if not.versão)

123 -> T [on integer]
-123 -> T [negative numbers need to be handled]
0 -> T [on zero]
123.456 -> T [on floating point]
123,456.789 -> T [on evenly divided by 3 digits with comas]
123456789 -> T [thousand separators are not required]
0000001.00000 -> T [on leading/trailing zeros]
00.00 -> T [on zero and leading/trailing zeros]
999999999.9999999999999999999999999999999999999999999999999999 -> T [on close to the maximum value]
-999999999.9999999999999999999999999999999999999999999999999999 -> T [on close to the minimum value]
 -> F [on empty]
lolz -> F [on non-number value]
n4melyh4xor -> F [on non-number with digits]
  1.2 -> F [on space-padded]
9.3 1.3 -> F [on anyhow separated multiple numbers]
1e5 -> F [no scientific notation]
50cl05e.buty3ts0f4r -> F [on input with letters obscuring the number]
1,2,3,4.5678 -> F [on badly readability-divided number]
1,234.5,678 -> F [on readability-divided floating point part]
.234 -> F [on no leading zero]
+1 -> F [no leading + sign]
1.234.3 -> F [only one decimal point]
12345,678 -> F [on separator stopping mid-way]

, menos caracteres é o vencedor.

n4melyh4xor
fonte
Podemos assumir que a entrada é sempre ASCII?
Brad Gilbert b2gills
@ BradGilbertb2gills, sim.
N4melyh4xor
Se -123estiver tudo bem, que tal +456-> bom ou ruim. Ou é +deixado de fora da festa?
chux - Restabelece Monica
@chux, o trem partiu antes do + chegar lá. Melhor sorte na próxima vez,.
N4melyh4xor
2
Quando as pessoas pedirem esclarecimentos nos comentários, você deve editar a pergunta. Nunca deve ser necessário ler os comentários para conhecer as especificações. Editei para incluir as respostas e alguns casos de teste.
Peter Taylor

Respostas:

10

Retina , 28 29 31 40 34 bytes

^-?\d{1,3}((,\d{3})*|\d*)(\.\d+)?$

Saídas 1se verdade, 0caso contrário. Pelo que entendi, nesse caso, a Retina gera o número de correspondências que o regex possui na entrada.

Experimente online!

Suíte de teste

Editar% s

  • Corrigido para obedecer à regra "deve haver dígitos após a casa decimal"
  • Corrigido para cumprir as regras de "lidar com negativos"
  • Corrigido para atender aos separadores de vírgula opcionais
  • Corrigido o erro com separadores de milhares, conforme observado por @MartinEnder
  • Jogou golfe removendo a cabeça de impressão condicional

RegExplanation

^-?\d{1,3}((,\d{3})*|\d*)(\.\d+)?$
^                                $  This marks the start and end of regex
 -?                                 Optional hyphen for negative number
   \d{1,3}                          Matches between 1 and 3 digits
          (             )           Capturing group
           (,\d{3})*                 Matches at least zero of comma and three numbers (in the case of separators)
                    |                OR
                     \d*             Matches at least zero digits (in the case of no separators)
                        (\.\d+)?    Matches an optional . and at least one digit (for decimal numbers)
Kritixi Lithos
fonte
@MartinEnder Fixed! Além disso, como você especifica os sinalizadores (digamos sinalizadores para me g) na Retina?
Kritixi Lithos
Coloque um `na frente do regex e os modificadores vão na frente dele, por exemplo m`^.$. gnão existe no .NET, as correspondências são globais por padrão.
22816 Martin Ender
3

JavaScript, 46 49 bytes

Esta é uma porta direta da minha resposta Retina. A única razão pela qual eu usei JS é para que haja uma maneira fácil de testar a regex usando o Snack Snippet abaixo

f=s=>/^-?\d{1,3}((,\d{3})*|\d*)(\.\d+)?$/.test(s)

f=s=>/^-?\d{1,3}((,\d{3})*|\d*)(\.\d+)?$/.test(s)
<input oninput=p.innerText=f(value)><p id=p></p>

Kritixi Lithos
fonte
Se não fosse por algumas das regras (como a regra da vírgula), poderia-se simplesmente fazer isNaN(+prompt())por 16 caracteres. Tal vida é, suponho
Matheus Avellar
2

Perl 6 , 42 bytes

{?/^\-?[\d**1..3[\,\d**3]+|\d+][\.\d+]?$/}

Tente

Expandido:

{  # bare block lambda with implicit parameter 「$_」

  ? # turn the following into a Bool result

  /  # match implicitly against 「$_」

    ^                 # beginning of string

    \- ?              # optional leading 「-」

    [

      \d ** 1..3      # 1 to 3 digits
      [
        \,            # comma
        \d ** 3       # three digits
      ]+              # repeat at least once

    |                 # or

      \d+             # at least one digit

    ]

    [ \. \d+ ]?       # 「.」 followed by at least one digit optionally

    $  # end of string

  /
}
Brad Gilbert b2gills
fonte
1

PHP, 62 bytes

<?=preg_match("#^-?(\d+|\d{1,3}(,\d{3})*)(\.\d+)?$",$argv[1]);

O builtin não pode manipular vírgulas e aceita notação científica; então eu tive que seguir o caminho regex. <?=is_numeric($argv[1]);teria sido de 24 bytes.

Titus
fonte
0

ferramentas bash / Unix, 64 bytes

egrep -c '^-?([0-9]+|[0-9]{1,3}(,[0-9]{3})+)(\.[0-9]+)?$'<<<"$1"

Salve isso como um arquivo e passe a string a ser testada como o primeiro argumento para o comando.

A saída é 0 para um não número, 1 para um número.

Se você estiver disposto a aceitar a entrada do stdin e se puder garantir que a entrada consiste em apenas uma linha, remova o <<< "$ 1" no final, resultando em 57 bytes .

Quanto ao próprio código, a opção -c para egrep conta o número de linhas correspondentes (que serão 0 ou 1).

Mitchell Spector
fonte
0

C89, 195 bytes

b,d,c,i;f(char*s){b=*s;for(d=c=i=0;i++,*(s++),d+=*s=='.',c+=*s==',',b=c?i&(i%4!=3)&*s==','?0:b:b;)if(*s==45&!i);else if((*s==32)|(*s==46)|*s==43|!isdigit(*s)&*s!=46&*s!=44)||!(d-1))b=0;return b;}

Ungolfed:

bool is_base10_number (const char* const str) {

  if(!str[0])return false;

  size_t
    dpts = 0,
    cmas = 0;

  for (size_t i = 0; i < strlen(str); i++) {

    if ((str[i] == '-') && (!i)){
      continue;
    }

    if (
      (str[i] == ' ')
      || (str[0] == '.')
      || (str[0] == '+')
      ||
      (
        (!isdigit(str[i]))
        && (str[i] != '.')
        && (str[i] != ',')
      )
    ) {
      return false;
    }

    dpts += str[i] == '.';
    cmas += str[i] == ',';

    if (cmas) {
      if (i & ((i % 4) != 3) & str[i] == ',') {
        return false;
      }
    }

  }

  if (dpts > 1) { return false; }

  return true;
}
gato
fonte
0

Python 2, 79 bytes

Solução Regex

import re
lambda s:[s]==re.findall('-?(?:\d{1,3}(?:,\d{3}\d+)(?:\.?\d+)?',s)


-?                                          | Starts with 0-1 dashes
  (?:\d{1,3}(?:,\d{3})+                     | Have 1-3 digits and 1+ (comma followed by 3 digits)
                       |\d+)                | or 1+ digits
                            (?:\.?\d+)?     | Ends with dot and 1+ digits or nothing

Experimente online

Gambá morto
fonte
0

c #, 75 bytes

bool t(string n){double v;return double.TryParse(n.Replace(",",""),out v);}
Johan du Toit
fonte