Verificação ordinal de string

17

Descrição :

Dada uma string como entrada, verifique se é um número ordinal válido em inglês ou não. Se for válido, retorne o valor verdadeiro, caso contrário, retorne o valor falso. (Sugerido por @Arnauld. Obrigado. Também por @JoKing)

Para usuários que desejam saber sobre números ordinais, acesse aqui:

https://www.mathsisfun.com/numbers/cardinal-ordinal-chart.html (sugestão de: qwr)

Entradas possíveis:

21st ---> true
12nd ---> false
1nd ---> false
....

Este é um desafio de código de golfe , pelo que o código mais curto em cada idioma será o vencedor.

Exemplos :

console.log('12th' , true) // This evaluates to true
console.log('1st' , true) // also evaluates to true
console.log('21nd' , false) // returns false
console.log('11st' , false) // returns false
console.log('111199231923819238198231923213123909808th' , true) // true

Como muitas pessoas fizeram a pergunta sobre se a entrada será apenas uma sequência válida ou não:

Todas as entradas sempre serão válidas. ou seja, eles terão a forma de sequência e consistirão em um dígito (ou número de dígitos) junto com um dos quatro sufixos:

st, nd, rd,th

Muhammad Salman
fonte
Você pode esclarecer as regras dos números ordinais? Ou pelo menos coloque um link para quais são as regras que você está seguindo.
Qd #
São regras normais. Eu não mudei nada. Mas, graças à entrada, eu adicionei um link
Muhammad Salman
Números @ Jonathan Allan ordinais começar a partir de 1st, não existem ordinais negativos - english.stackexchange.com/questions/309713/...
Oliver Ni
@ JonathanAllan OP diz que "a entrada será um padrão ordinal válido". o que significa que não há negativos
Oliver Ni
2
Você diz que as entradas sempre serão válidas, mas acho que um termo melhor seria bem formado . Ambos os dias 12 e 12 são bem formados, mas apenas o primeiro é válido .
21818 David Conrad

Respostas:

3

Utilitários Bash + GNU , 54

A correspondência de regex parece ser um caminho simples a seguir. Tenho certeza de que essa expressão poderia ser reduzida mais:

egrep '((^|[^1])(1st|2nd|3rd)|(1.|(^|[^1])[^1-3])th)$'

Entrada de STDIN. Saída como um código de retorno do shell - 0 é verdade e 1 é falsey.

Experimente online!

Trauma Digital
fonte
O que ? isso não está gerando a resposta correta.
Muhammad Salman
@MuhammadSalman Isso é porque é uma suíte de testes. Dê uma olhada nos códigos de saída para 1ste 1th.
Dennis
egrepé capaz de testes de adição e primalidade (em unário), então acho que você pode fazer disso uma resposta egrep.
21418 Dennis
Sinto muito, mas minha festa é uma merda, pois não tenho idéia de nada. Fiquei entediado, então usei um verificador de diferenças para verificar a diferença entre entrada e saída. Eu entendo o seu ponto. Então, eu tenho uma pergunta agora @Dennis: O Bash tem booleanos?
Muhammad Salman
Talvez os casos de teste sejam mais claros se egrepforem executados separadamente para cada entrada para obter o código de saída correspondente para cada um: Experimente online! .
precisa saber é
3

isso está sob a suposição de que a entrada é um padrão ordinal válido. se não for o caso, é necessário fazer alterações

JavaScript (Node.js) , 97 92 78 bytes

s=>("tsnr"[~~((n=(o=s.match(/(\d{1,2})(\D)/))[1])/10%10)-1?n%10:0]||'t')==o[2]

Experimente online!

Explicação

s=>
   ("tsnr"                                // all the options for ordinal - 4-9 will be dealt afterwards    
      [~~(                                //floor the result of the next expression
        (n=(                              //save the number (actually just the two right digits of it into n
          o=s.match(/(\d{1,2})(\D)/))[1]) //store the number(two digits) and the postfix into o (array)
        /10%10)-1                         //if the right most(the tenths digit) is not 1 (because one is always 'th')
          ?n%10:0]                        //return n%10 (where we said 0-3 is tsnr and afterwards is th
            ||'t')                        // if the result is undefined than the request number was between 4 and 9 therefor 'th' is required
    ==o[2]                                // match it to the actual postfix  

_____________________________________________________________________

porto de @Herman Lauenstein

JavaScript (Node.js) , 48 bytes

s=>/1.th|(^|[^1])(1st|2nd|3rd|[^1-3]th)/.test(s)

Experimente online!

DanielIndie
fonte
Se a solução pressuposto reg também pode ser***.
l4m2
Se não for assumido que é / \ d * (st | nd | rd | th) / input, 1stapasse no teste de registro; se assumido, /1.th|(^|[^1])(1s|2n|3r|[^1-3]t)/trabalho
l4m2 14/04
3

Python ,  56  53 bytes

-3 graças a (use inclusão de letra exclusiva em vez da penúltima igualdade de caracteres)

lambda v:'hsnrhhhhhh'[(v[-4:-3]!='1')*int(v[-3])]in v

Uma função sem nome.

Experimente online!

Quão?

Desde toda entrada (aqui v) é garantido para ser da forma \d*[st|nd|rd|th]nós podemos apenas testar se um personagem existe na vqual esperamos estar lá se fosse correto ( s, n, r, ou h, respectivamente) - que é <getExpectedLetter>in v.

O último dígito geralmente determina isso:

v[-3]: 0 1 2 3 4 5 6 7 8 9
v[-2]: h s n r h h h h h h

... exceto quando o penúltimo dígito é a 1, quando tudo deve terminar com the, portanto, nosso caráter esperado deve ser h; para avaliar isso, podemos tirar uma fatia (para evitar um erro de índice ocorrendo há entradas sem -4 th personagem) v[-4:-3]. Desde os 0mapas para hjá, podemos alcançar o efeito desejado usando a multiplicação antes da indexação 'hsnrhhhhhh'.

Jonathan Allan
fonte
st, nd, rd e th todos têm uma única letra para que você pode apenas testar se ele ocorre na seqüência de 53 bytes
asone Tuhid
@AsoneTuhid nice golf - thanks!
Jonathan Allan
@AsoneTuhid - também economizei três na minha resposta Jelly, então o dobro do obrigado!
Jonathan Allan
3

Java 8, 54 51 bytes

s->s.matches(".*1.th|(.*[^1])?(1s|2n|3r|[^1-3]t).")

Explicação:

Experimente online.

s->  // Method with String parameter and boolean return-type
  s.matches(".*1.th|(.*[^1])?(1s|2n|3r|[^1-3]t).")
     //  Validates if the input matches this entire regex

A String # do Java corresponde implicitamente a adiciona ^...$.

Explicação Regex:

^.*1.th|(.*[^1])?(1s|2n|3r|[^1-3]t).$
^                                          Start of the regex
 .*1.                                       If the number ends in 11-19:
     th                                      it must have a trailing th
       |                                    If not:
        (.*    )?                            Optionally it has leading digits,
           [^1]                              excluding a 1 at the end
                 (1s|2n|3r         .      followed by either 1st, 2nd, 3rd,
                          |[^1-3]t).      0th, 4th, 5th, ..., 8th, or 9th
                                    $   End of the regex
Kevin Cruijssen
fonte
2

Pitão, 49 bytes SBCS

Js<2zK%J100I||qK11qK12qK13q>2z"th".?qz+J@c."dt8¸*£tÎðÎs"2J

Suíte de teste

O SE comeu alguns imprimíveis no código (e na explicação abaixo), mas eles estão presentes no link.

Explicação:
Js<2zK%J100I||qK11qK12qK13q>2z"th".?qz+J@c."dt8¸*£tÎðÎs"2J # Code
Js<2z                                                         # J= the integer in the input
     K%J100                                                   # K=J%100
           I||qJ11qJ12qJ13                                    # IF K is 11, 12, or 13:
                          q>2z"th"                            #  Print whether the end of the input is "th"
                                  .?                          # Otherwise:
                                    qz                        #  Print whether the input is equal to
                                      +J                      #   J concatenated with
                                        @                   J #    The object at the Jth modular index of
                                          ."dt8¸*£tÎðÎs"   #     The string "thstndrdthththththth"
                                         c                 2  #      Chopped into strings of length 2 as a list
Tradução Python 3:
z=input();J=int(z[:-2]);K=J%100
if K==11or K==12or K==13:print(z[-2:]=="th")
else:print(z==str(J)+["thstndrdthththththth"[2*i:2*i+2] for i in range(10)][J%10])
hakr14
fonte
2

Python 2, 92 82 74 68 bytes

-8 graças a Chas Brown
-6 graças a Kevin Cruijssen

lambda s:(a+'t'*10+a*8)[int(s[-4:-2]):][:1]==s[-2:-1]
a='tsnr'+'t'*6

Constrói uma grande cadeia de th s, sts, nds, e rdé para terminações 00para 99. Em seguida, verifica se ele corresponde.

Oliver Ni
fonte
2

Retina , 35 31 bytes

-4 bytes graças a @Asone Tuhid

Obrigado ao @Leo por encontrar um bug

1.th|(^|[^1])(1s|2n|3r|[04-9]t)

Saídas 1para verdadeiro e 0para falso. Isso pressupõe que a entrada esteja no formato ordinal com um sufixo válido (termina com st,nd , rdou th).

Experimente online!

Herman L
fonte
1

Perl 5 -n , 57 bytes

/..$/;say$&eq(th,st,nd,rd,(th)x6)[$_%100-$_%10-10&&$_%10]

Experimente online!

Xcali
fonte
1

Geléia ,  25  22 bytes

-3 bytes graças a uma observação feita em um comentário feito por minha entrada em Python.

ḣ-2VDṫ-’Ạ×ɗ/«4ị“snrh”e

Um link monádico.

Experimente online! Ou veja a suíte de testes .

Quão?

ḣ-2VDṫ-’Ạ×ɗ/«4ị“snrh”e - Link: list of characters   e.g. "213rd" or "502nd" or "7th"
ḣ-2                    - head to index -2                "213"      "502"      "7"
   V                   - evaluate                         213        502        7
    D                  - cast to decimal list            [2,1,3]    [5,0,2]    [7]
     ṫ-                - tail from index -1                [1,3]      [0,2]    [7]
           /           - reduce with:                                          (no reduction since already length 1)
          ɗ            -   last 3 links as a dyad:                           
       ’               -     decrement (the left)           0         -1        x
        Ạ              -     all? (0 if 0, 1 otherwise)     0          1        x
         ×             -     multiply (by the right)        0          2        x
            «4         - minimum of that and 4              0          2        4
              ị“snrh”  - index into "snrh"                 'h'        'n'      'h'
                     e - exists in? (the input list)        0          1        1
Jonathan Allan
fonte
0

05AB1E , 24 bytes

0ìþR2£`≠*.•’‘vê₅ù•sèsáнQ

Experimente online! ou como um conjunto de testes

Explicação

0ì                         # prepend 0 to input
  þ                        # remove letters
   R                       # reverse
    2£                     # take the first 2 digits
      `≠                   # check if the 2nd digit is false
        *                  # and multiply with the 1st digit
         .•’‘vê₅ù•         # push the string "tsnrtttttt"
                  sè       # index into this string with the number calculated
                    sáн    # get the first letter of the input
                       Q   # compare for equality
Emigna
fonte
0

Rubi , 42 39 bytes

Lambda:

->s{s*2=~/1..h|[^1](1s|2n|3r|[4-90]t)/}

Experimente online!

Entrada do usuário:

p gets*2=~/1..h|[^1](1s|2n|3r|[4-90]t)/

Experimente online!

Partidas:

  • 1(anything)(anything)h - 12th
  • (not 1)1s - (1st)
  • (not 1)2n - (2nd)
  • (not 1)3r- ( 3rd)

Como [^1]( not 1) não corresponde ao início de uma sequência, a entrada é duplicada para garantir que haja um caractere antes da última.


Ruby -n , 35 bytes

p~/1..h|([^1]|^)(1s|2n|3r|[4-90]t)/

Experimente online!

A mesma idéia que acima, mas em vez de duplicar a string, isso também corresponde ao início da string ( ^).

Asone Tuhid
fonte
0

Excel, 63 bytes

=A1&MID("thstndrdth",MIN(9,2*RIGHT(A1)*(MOD(A1-11,100)>2)+1),2)

(MOD(A1-11,100)>2)retorna FALSEquando A1termina com 11-13

2*RIGHT(A1)*(MOD(A1-11,100)>2)+1retornos 1Se está em 11- 13e 3, 5,7 , etc. de outra forma

MIN(9,~)muda todos os retornos acima 9para 9puxar oth partir da cadeia

MID("thstndrdth",MIN(~),2)extrai o primeiro thpara entradas que terminam em 11- 13, stpara 1, ndpara 2, rdpara 3e o últimoth para algo mais alto.

=A1&MID(~) Anexa o número original ao ordinal.


Postando como wiki, já que eu não sou o autor disso. ( Fonte )

Engineer Toast
fonte
0

Língua Wolfram (Mathematica) , 122 bytes

Diferentemente da maioria das outras respostas aqui, isso realmente retornará false quando a entrada não é um "padrão ordinal válido", portanto, retornará corretamente false na entrada como "3a23rd", "monkey" ou "╚§ +!". Então, acho que isso funciona para todo o conjunto de possíveis strings de entrada.

StringMatchQ[((d=DigitCharacter)...~~"1"~(e=Except)~d~~(e["1"|"2"|"3",d]~~"th")|("1st"|"2nd"|"3rd"))|(d...~~"1"~~d~~"th")]

Experimente online!

Kelly Lowder
fonte
0

Wolfram Language (Mathematica) , 65 59 bytes

SpokenString@p[[#]]~StringTake~{5,-14}&@@ToExpression@#==#&

Experimente online!

É claro que o Mathematica possui um built-in (embora não documentado) para converter em número ordinal. Fonte .

(para a versão de 65 bytes: de acordo com isso, parece que a v9 e anterior não precisam ser chamadas Speak antes, para que seja possível salvar mais alguns bytes)

Verifique também a resposta de KellyLowder para obter uma versão não incorporada .

user202729
fonte
0

PHP, 60 bytes

chato: regexp mais uma vez a solução mais curta

<?=preg_match("/([^1]|^)(1st|2nd|3rd|\dth)$|1\dth$/",$argn);

saída vazia por falsidade, 1 por verdade.

Execute como pipe -nFou experimente online . (TiO envolvido como função por conveniência)

Titus
fonte
0

código de máquina x86, 65 bytes

00000000: 31c0 4180 3930 7cfa 8079 0161 7ef4 8079  1.A.90|..y.a~..y
00000010: ff31 7418 31db 8a19 83eb 308a 9300 0000  .1t.1.....0.....
00000020: 0031 db43 3851 010f 44c3 eb0a 31db 4380  .1.C8Q..D...1.C.
00000030: 7901 740f 44c3 c374 736e 7274 7474 7474  y.t.D..tsnrttttt
00000040: 74                                       t

Montagem:

section .text
	global func
func:					;the function uses fastcall conventions
					;ecx=first arg to function (ptr to input string)
	xor eax, eax			;reset eax to 0
	read_str:
		inc ecx			;increment ptr to string

		cmp byte [ecx], '0'
		jl read_str		;if the char isn't a digit, get next digit
		cmp byte [ecx+1], 'a'
		jle read_str		;if the char after the digit isn't a letter, get next digit
		cmp byte [ecx-1], '1'
		je tens 		;10-19 have different rules, so jump to 'tens'
		xor ebx, ebx		;reset ebx to 0
		mov bl, byte [ecx]  	;get current digit and store in bl (low byte of ebx)
		sub ebx, 0x30		;convert ascii digit to number
		mov dl, [lookup_table+ebx] ;get correct ordinal from lookup table
		xor ebx, ebx		;reset ebx to 0
		inc ebx			;set ebx to 1
		cmp byte [ecx+1], dl	;is the ordinal correct according to the lookup table?
		cmove eax, ebx		;if the ordinal is valid, set eax (return reg) to 1 (in ebx)
		jmp end			;jump to the end of the function and return

		tens:
		xor ebx, ebx		;reset ebx to 0
		inc ebx			;set ebx to 1
		cmp byte [ecx+1], 't'	;does it end in th?
		cmove eax, ebx		;if the ordinal is valid, set eax (return reg) to 1 (in ebx)

	end:
	ret				;return the value in eax
section .data
	lookup_table db 'tsnrtttttt'

Experimente online!

Logern
fonte
-1

Expressão regular compatível com Perl, 29 bytes

1.th|(?<!1)(1s|2n|3r)|[4-90]t

Aceitamos thapós qualquer número "adolescente" ou após qualquer dígito que não seja 1..3. Para 1..3, usamos um lookbehind negativo para aceitar st,nd ou rdsomente quando não precedido por 1.

Programa de teste

#!/usr/bin/bash

ok=(✓ ❌)

for i
do grep -Pq '1.th|(?<!1)(1s|2n|3r)|[4-90]t' <<<"$i"; echo $i ${ok[$?]}
done 

Resultados

1st ✓
1th ❌
2nd ✓
2th ❌
3rd ✓
3th ❌
4st ❌
4th ✓
11th ✓
11st ❌
12nd ❌
12th ✓
13th ✓
13rd ❌
112nd ❌
112th ✓
21nd ❌
32nd ✓
33rd ✓
21th ❌
21st ✓
11st ❌
111199231923819238198231923213123909808th ✓
Toby Speight
fonte