Números de telefone ilegíveis

19

Você sabe como recebe uma mensagem de correio de voz e a conexão da pessoa não é ótima, e está tentando descobrir como chamá-la de volta, mas não sabe ao certo se era um "5" ou um "8". disse?

Esse é esse desafio.

A boa notícia é que o interlocutor leu o número duas vezes, mas está truncado nos dois lugares.

Seu programa deve receber informações como estas:

5551231234 / 5551231234

Onde os dez primeiros dígitos são a primeira vez que o número de telefone é dito no correio de voz e o segundo conjunto é a segunda vez que é dito. Apenas ... ficará mais ou menos assim:

555?ABC1_36? / 55?522_1?234
  • Um dígito seguido de um ponto de interrogação significa que essa é a melhor estimativa para esse dígito (por exemplo, "5?" Significa "provavelmente um 5, compare com repetir").
  • Um sublinhado indica um dígito ausente conhecido, algo muito distorcido pela estática para ser decifrado.
  • Cartas são exatamente isso: cartas. Trate-os como seus respectivos dígitos
    • ABC -> 2, DEF -> 3, GHI -> 4, JKL -> 5, MNO -> 6, PQRS -> 7, TUV -> 8, WXYZ -> 9
    • Todas as entradas de amostra usam maiúsculas (você pode omitir com segurança uma chamada de ToUpper ())
    • Se seu idioma funcionar melhor em letras minúsculas, você poderá usar livremente letras minúsculas para a entrada e omitir uma chamada ToLower (). Apenas observe isso em sua resposta.

Além disso, você pode assumir as seguintes chamadas de julgamento:

5? / _     -> 5  //5 is the best guess we have, use it
5? / 5?    -> 5  //uncertain, but matching
5? / 4?    -> ?  //conflict
 5 / 4     -> ?  //conflict
5? / 4     -> 4  //solid information overrides possible value
 5 / 4?    -> 5  //solid information overrides possible value
 _ / _     -> ?  //no information available

Além disso, você pode assumir que todas as entradas conterão números de telefone de dez dígitos, sem incluir os pontos de interrogação. As entradas que não têm dez dígitos (por exemplo 1234567 / 1234567) podem ser tratadas como insolúveis (saída falsey) ou gerar um erro.

Entrada

Uma linha de caracteres 0-9A-Z _?/, conforme descrito acima.

Resultado

Se puder ser analisado para um único número de telefone válido de dez dígitos, produza o número de telefone. Caso contrário, imprima alguma forma de indicação de erro (por exemplo, -1, falso ou uma linha vazia).

Vitórias mais curtas, como de costume.

Entradas de amostra:

1234567890 / 1234567890
1234567890? / 1234567890
123456789_ / 1234567890
1234567890? / 123456789_
1234567890 / 1234567890?
1234567890 / 123456789_
123456789_ / 1234567890?
1234567890? / 1234567890?
1234567890? / 1234567891?
123456789_ / 123456789_
555CALLUS1 / 5552255871
404_12?6039 / 4041?1560_9
_GETREVENGE / 16?36?_2838_
1?691460_50 / 16_14609?50
61?08977211 / 612?897725?1
40?0INSTA__ / 8?00_NSTI?LL
3985_534?10 / 39?8?5053_10
7__7294?737 / 7797299?_37
28?897_384?1 / _8?89763861
271168090_ / 27116800?09
6802?148343 / 67?01148343
94_11628?2?6? / 9491162_47?
17?4285_689 / 1__26?52689
6_311?95_38 / 6731194?7?38
380?7DRAGON / 3807378?5?66
4?647_93236 / 5646?6?9__36
365?268898_ / 366267?7?984
GRATEDBATE / IRATEDBATE
5307_079?93 / ____8_____
535_3_0255 / 52?5_3_024?5
55_____088 / 54?2397207?7?
6_48398_95 / _946?398?6_5?
_0_312_3_1 / 81?53123?1?71
____1_____ / 64?255?508?61
8427820607 / 6?424?8?__6?07
50_3707__6 / 52?8375?74?56
615___8255 / 62?526?983?2?1?
__652618__ / 8365261__0
149___933_ / 1_9677?92?31
___7?281562 / 3438?28154?2
5?7?7?___8?3?7?4 / 57_855837_
605_272481 / 605427__81
86?569__731 / 88560?0?7721
1__91654?15 / 17?9?9165715
800NWABODE / 80069ABI?DE
8___9017_0 / 8_2494?12?9_
_024?5?91?470 / 304?17908?7_
42510704_2 / 4_51070492
9338737_89 / 93_873PLUS
327762_401 / 327_MASH01
33093_2058 / 3309_12058
4061_33578 / 40619_3578
559_383197 / 559938_197
94_9746084 / 9459746_84
1_37655238 / 163POLKA_T
_672FRIZZY / 767237499_
8_76318872 / TIP63188_2
51_8404321 / 5178404_21
358_030314 / 358603_314
2597_85802 / 25979_5802
77141_1408 / 7714_91408
330858_457 / 330_586457
4686079_39 / 46_6079239
86457508_6 / 8_45750826
523226626_ / _23BANNANA
_ISSY_ISSY / 44__9548?79?
6?00B_YJILT / 800289KILL?
2?52803___0 / 1526?0390?61?
FI?ND___T?HE / EAS?T?EREGGS?
0_231?95_38 / 0723194?7?38
0?647_39236 / 0646?6?3__36
025?267798_ / 06?6265?9?984
0061_33578 / _0619_3578

Eu só garanti que todos os casos extremos possíveis sejam cobertos (as 11 primeiras entradas), mas fora isso, é praticamente aleatório.

Atualizar

Quatro entradas na parte inferior foram adicionadas com zeros à esquerda (por sugestão de Jonathan Allan).

Saída correta para as entradas de amostra:

https://pastebin.com/gbCnRdLV

Com base na saída da entrada de Jonathan Allan (a saída formatada era ideal).

Draco18s
fonte
Temos que tomar as entradas como uma única string, separadas por " / ", ou podemos apenas tomá-las como duas entradas padrão?
L3viathan
@ L3viathan Eu originalmente concebi a ideia como tendo que usar uma única string.
Draco18s
7
@ Draco18s corda única não traz nada para o desafio
fənɛtɪk
11
@ fəˈnɛtɪk Ninguém disse nada na sandbox, mas não tenho nada contra o uso de pares de entrada. Foi exatamente como eu o concebi originalmente.
precisa saber é o seguinte
11
Quem deixa um correio de voz usando letras para o número de telefone ?!
Jonathan Allan

Respostas:

3

Geléia , 84 bytes

+4 bytes - acho que provavelmente deve se comportar da mesma forma em todos os casos, então converti os números inteiros de pesquisa do teclado de volta para dígitos digitados usando +49Ọ.

”?e‘ḣ@µ”_eḤ‘ẋ@
;Ṃµ68DṬ+3RØAṁẇ@€FT+49Ọȯµ€Fṡ2i”?Ḃ$ÐḟÇ€
ḟ⁶ṣ”/Ç€ZLÐṂ€Q€LỊ$ÐfF€Ḣ€ḟ”_µL⁼⁵ȧ

Uma função que pega a sequência no formato especificado e retorna o número de telefone como uma lista de caracteres ou zero, se inválido. Como um programa, isso é impresso como se fosse uma string.

Da maneira que funciona, eles podem repetir o número mais vezes
(por exemplo "123456789_ / 123456789_ / 1234567890")
... ou até mesmo dizê-lo apenas uma vez, e a lógica definida será aplicada.

Experimente online! ou veja todas as entradas de amostra .

Quão?

”?e‘ḣ@µ”_eḤ‘ẋ@ - Link 1, helper to vary the length of a 2-slice: list s
”?             - literal '?'
  e            - exists in s                   (1 or 0)
   ‘           - increment                     (2 or 1)
    ḣ@         - head with reversed @rguments  (s or s[:1] - removes 2nd value if not '?')
      µ        - monadic chain separation, call that t
       ”_      - literal '_'
         e     - exists in t                   (1 or 0)
          Ḥ    - double                        (2 or 0)
           ‘   - increment                     (3 or 1)
            ẋ@ - repeat t that many times      (t*3 or t - [`_`]->['_','_','_'])

;Ṃµ68DṬ+3RØAṁẇ@€FT+49Ọȯµ€Fṡ2i”?Ḃ$ÐḟÇ€ - Link 2, reformat a phone number: char list of [0-9][A-Z], p
;                                     - concatenate p with
 Ṃ                                    - minimum of p - (?<_<0<1<...<9<A<...<Z - never "?" however, since it only follows a digit.)
                                      -   - this is simply to make a 2-slice with the last character on the left, as used at the very end of this link.
  µ                                   - monadic chain separation call that q
                       µ€             - monadic chain separation, for €ach v in q do:
   68                                 -   literal 68
     D                                -   cast to a decimal list -  [6,8]
      Ṭ                               -   untruth                -  [0,0,0,0,0,1,0,1]
       +3                             -   add 3                  -  [3,3,3,3,3,4,3,4]
         R                            -   range                  -  [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3,4],[1,2,3],[1,2,34]]
          ØA                          -   uppercase alphabet     -  ABCDEFGHIJKLMNOPQRSTUVWXYZ
            ṁ                         -   mould like the range ^ -  [ABC,DEF,GHI,JKL,MNO,PQRS,TUV,WXYZ]
             ẇ@€                      -   sublist v exists in that? for €ach, with reversed @rguments
                F                     -   flatten        (e.g. 'E' -> [0,1,0,0,0,0,0,0]; '4' -> [0,0,0,0,0,0,0,0]
                 T                    -   truthy indexes (e.g. 'E' -> [2]; '4' -> [])
                  +49                 - add 49
                     Ọ                - cast to character
                      ȯ               -   or             (e.g. 'E' -> [3]; '4' -> '4')
                         F           - flatten
                          ṡ2          - all slices of length 2
                                 Ðḟ   - filter discard if:
                                $     -   last two links as a monad:
                            i         -     first index of
                             ”?       -     literal '?'   (first index returns 0 if none exists)
                               Ḃ      -   mod 2 (so this filter discards pairs starting with '?')
                                   Ç€ - call the last link (1) as a monad for €ach slice

ḟ⁶ṣ”/Ç€ZLÐṂ€Q€LỊ$ÐfF€Ḣ€ḟ”_µL⁼⁵ȧ - Main link: string (or char list) s
ḟ                               - filter discard any:
 ⁶                              - literal ' '
  ṣ                             - split on:
   ”/                           - literal '/'
     Ç€                         - call the last link (2) as a monad for €ach
       Z                        - transpose
         ÐṂ€                    - filter, for €ach, keep items with minimal:
        L                       -   length
            Q€                  - de-duplicate €ach
                 Ðf             - filter keep items with:
                $               - last two links as a monad:
              L                 -   length
               Ị                -   insignificant? (=1 effectively here)
                   F€           - flatten €ach
                     Ḣ€         - head €ach
                       ḟ        - filter discard any of:
                        ”_      -   literal '_'
                          µ     - monadic chain separation, call that r
                           L    - length(r)
                             ⁵  - literal 10
                            ⁼   - equal?
                              ȧ - and r (0 if r did not result in a 10-digit list, else r)
Jonathan Allan
fonte
Parece que pode haver um erro, 55_____088 / 54?2397207?7?deve resolver 5523972088: todos os dígitos ausentes estão presentes e os dígitos incertos à direita estão disponíveis à esquerda. Todos os casos simplistas são executados.
Draco18s
Ah, eu removi o que eu pensava ser um filtro redundante, não era. Corrigindo ...
Jonathan Allan
Estive lá antes - e não era golfe! ;)
Draco18s
Ooof que demorou um pouco (eu encontrei um bug diferente enquanto o estava testando), retornei à mesma contagem de bytes que apenas adicionei o filtro novamente ao consertá-lo (ufa).
Jonathan Allan
@ Draco18s - tudo parece bom para você? Pode ser bom fornecer a saída esperada para os casos de teste da pergunta ou talvez apenas separar os inválidos.
Jonathan Allan
7

Python 2 , 314 307 274 bytes

lambda s:g(*''.join(q<n<"["and`(int(n,36)-4-(n>"R")-(n>"Y"))//3`or n for n in s).split(" / "))
def g(a,b,s=str.startswith):
 if b:c,d,e,f=a[0],a[1:],b[0],b[1:];b=(c==e and[c,q][c=="_"]or"_"in c+e and min(c,e)or[q,c,e][s(f,q)-s(d,q)])+g(d[s(d,q):],f[s(f,q):])
 return b
q="?"

Experimente online!

ovs
fonte
5

Python 3, 549 530 509 453 449 410 406 394 393 391 bytes

Tenho certeza que isso pode ser melhorado, mas é um começo:

def f(e,z,q="?",u=str.isnumeric):
 if e+z in(e,z):return""
 o,O,t,T,*x=e[0],e[1:2],z[0],z[1:2],e[1:],z[1:]
 if"?"in o+t:return f([e,x[0]][o==q],z)
 if u(o):
  if u(t):return t+f(*x)if O==q!=T else o+f(*x)if o==t or T==q!=O else 1
  return o+f(*x)
 if u(t):return t+f(*x)
def g(s):
 for a,b in zip(map(chr,range(65,91)),"2223334445556667777888999"):s=s.replace(a,b)
 return f(*s.split(" / "))

Estou usando str.translateas letras e uma função de invólucro gpara fazer as entradas no formato em que as quero. A função realf é recursiva e falhará para entradas ambíguas. Ainda tenho muitas repetições por lá, então tenho certeza de que há muito espaço para melhorias.

Melhorias:

  • economizou 19 bytes combinando condições
  • salvou 21 bytes com ternários
  • economizou 56 bytes usando a compreensão do dicionário em vez do dicionário manual, graças a @TuukkaX
  • salvou 4 bytes mudando para o método sugerido por @ovs, com a melhoria do @ TuukkaX
  • salvou 38 bytes com melhorias do @ovs (e o último espaço em branco removível removido)
  • salvou 4 bytes colocando definição str.isnumericem um argumento de palavra-chave
  • salvou 12 bytes com operadores de comparação combinados (por exemplo, T==q!=O )
  • economizou 1 byte girando not(e or z) em e+z in(e,z).
  • salvou 2 bytes salvando o arquivo freqüentemente usado (E,Z)
L3viathan
fonte
Isso contém uma compreensão do dicionário que não contém os padrões da linha superior. Eu odeio as seqüências de 3, mas essas podem ser substituídas por matemática.
Yytsi
@ovs Nice. O alfabeto pode ser alterado para map(chr,range(65,91))embora.
Yytsi
2
RE: Fazendo deste um wiki da comunidade para renunciar à reputação, o consenso seria não , basta aceitar a ajuda gentil e creditar como você tem.
Jonathan Allan
11
Juro que toda vez que volto aqui, essa resposta fica mais curta: D
Draco18s
3

JavaScript (ES6), 180 190 188 bytes

Editar: +10 +9 bytes para obedecer à regra de saída falsa


Pega as duas seqüências de entrada na sintaxe de currying (a)(b). Retorna uma falseou uma sequência que representa o número de telefone adivinhado.

a=>b=>!(s=(F=a=>a.match(/(.\??)|_/g).map(([x,y])=>(x<=9?++x:parseInt(x,36)*.32-(x>'Y'))|(x!='_'&!y)*16))(a).map((x,i)=>(x=(d=x^(y=F(b)[i]),x>y)?x:y)&&(d&16|!(d%x))?--x&15:a).join``)[10]&&s

Como funciona

Etapa 1 - Analisando as seqüências de entrada

Primeiro, definimos o F() função que traduz uma string em uma matriz de números inteiros aplicando as seguintes regras:

  • o sublinhado é convertido em 0
  • um dígito N ou uma letra equivalente é convertido em (N + 1) OU 16 (por exemplo, "2" → 19, "R" → 24)
  • um dígito N ou uma letra equivalente seguida por uma marca de interrogação é convertida em N + 1 (por exemplo, "2?" → 3, "R?" → 8)

O que pode ser interpretado ao contrário da seguinte maneira:

  • 0 desconhecido
  • [ 1 .. 10 ]não confiável
  • [ 17 .. 26 ]confiável

Nós aplicamos F()a ambos ae b. Isso nos fornece um par de números inteiros (x, y) para cada dígito no número de telefone, correspondendo às duas interpretações possíveis.

Etapa 2 - Adivinhando os dígitos

Para cada par (x, y) , calculamos:

  • d = x XOR y
  • x = MAX (x, y) valores confiáveis ​​são sempre preferidos a valores não confiáveis

Se x == 0 , significa que ambas as entradas são caracteres sublinhados. Portanto, o dígito é desconhecido neste caso.

Se x! = 0 , podemos deduzir com segurança o dígito se uma das seguintes condições for verdadeira:

condition       | interpretation
----------------+------------------------------------------------------
(d AND 16) != 0 | one input is unreliable and the other one is reliable
d == 0          | both inputs are identical
d == x          | one input is an underscore

As duas últimas condições podem ser mescladas !(d % x). Daí a fórmula final:

x && (d & 16 || !(d % x))

Se verdadeiro, convertemos x de volta ao dígito calculado calculando (x - 1) E 15 .

Casos de teste

(Somente os 50 primeiros, porque o snippet do console não suporta mais histórico de saída.)

Arnauld
fonte
1234567890? / 1234567890?deve resolver a 1234567890. No momento, o seu código gera 123456789?menos informações do que a entrada. Assume: 5? / 5? -> 5 //uncertain, but matching
Draco18s
@ Draco18s Ao contrário do que afirmei, incluí 51 casos de teste. Então o primeiro foi descartado e tudo mudou em uma linha. (Agora fixo Desculpe por isso..)
Arnauld
Aaah. Ainda assim, deve gerar algum tipo de valor de falsey ou erro para esses casos de teste. Mas, caso contrário, parece ser bom.
Draco18s
2

Perl 5 , 211 bytes

... sem recuo e \ n novas linhas

@i=map{y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/22233344455566677778889999/;$_}split' / ',shift;
print map{
  $_=join'',map{s,(\d\??|_),,;$1}@i;
  /((\d)\??\2\??|(\d)\??_|_(\d)\??|(\d)\d\?|\d\?(\d))$/;$2//$3//$4//$5//$6//'?'
}1..10

Experimente online!

Kjetil S.
fonte
Parece que está retornando "o melhor que pode" ( 83652618?0), em vez de algum tipo de valor falsa ou de erro.
Draco18s
Qual é o que o quebra-cabeça queria se não me engano. Veja os casos sob o título "Você também pode assumir as seguintes chamadas de julgamento". Ou não?
precisa
Desculpe, nunca recebi uma notificação da sua resposta (sem mencionar). A seção que eu tinha feito para os julgamentos usa um ?para indicar que não há nenhuma maneira de resolver a informação em falta, que deve, então, cair para a seção de saída:...Otherwise output some form of error indication (e.g. -1, false, or an empty line).
Draco18s
2

Retina, 150 140 136 bytes

Economizou alguns bytes graças a Kritixi Lithos

T`?L`#22233344455566677778889
./.

(?<=(\d)(\w#?){9}).#|.#(?=(\w#?){9}(\d)(?!#))
$1$4
#

_(?=.{9}(.))|(?<=(.).{9})_
$1$2
^(\d*)\1$|.*
$1

Experimente Online!

Explicação:

A primeira linha transforma tudo ?na entrada em #e todas as letras em seus equivalentes numéricos. Em seguida, removemos os espaços e /da entrada. As próximas duas linhas tratam dos casos de "palpite versus certeza" (por exemplo, 5? \ 4seriam substituídos por 4 \ 4). Depois de remover todos os #s, as linhas 8 e 9 tratam dos _casos "número vs. " ( _ \ 3torna-se 3 \ 3). Então, se as duas metades da string corresponderem, mantemos os 10 primeiros dígitos. Caso contrário, o número de telefone é inválido, portanto, removemos tudo.

Solução alternativa de 160 bytes que funciona para números de telefone de tamanho arbitrário (e tamanho igual): TIO

viciado em matemática
fonte
Você pode alterar (/|_)para [/_]para salvar 1 byte. Também acho que você pode usar ;em vez de xmodo que [^x]pode se tornar\w
Kritixi Lithos
1

PHP, 251 236 bytes

for(;a&$c=preg_replace(["#[^_?](?!\?)#","#_#"],["$0k","?<"],join("-",$argv))[++$i];)${$k+="-"==$c}.=$c<_&$c>=A?0|(ord($c)-($c>W)-($c>P)-59)/3:$c;for(;$c=${1}[$k+1];)echo($n=${1}[$k])==($m=${2}[$k++])|($b=${2}[$k++])!=$c?$c>$b?$n:$m:"?";

recebe entrada da linha de comando; correr com-nr ou experimente online .

demolir

# A: transform input
                                    # 2. replace single chars with two-character chunk and make sortable:
                                    #   replace "_" with "?<", append "k" to everything else not followed by "?"
for(;a&$c=preg_replace(["#[^_?](?!\?)#","#_#"],["$0k","?<"],join("-",$argv))[++$i];)    # (unknown "<" < unsure "?" < certain "k")
${$k+="-"==$c}.=                # if "-", next argument
        $c<_&$c>=A              # if letter
            ?0|(ord($c)-($c>W)-($c>P)-59)/3 # then translate to digit
            :$c                             # else don´t
    ;
# B: evaluate
for(;$c=${1}[$k+1];)            # loop through arguments: $c=command 2
    echo
        ($n=${1}[$k])                   # $n=digit 2
        ==                          # if digits are equal
        ($m=${2}[$k++])                 # $m=digit 3
        |
        ($b=${2}[$k++])             # $b=command 3
        !=$c                        # or "commands" are not
            ?$c>$b?$n:$m            # then get the one with the more definitive "command"
            :"?"                    # else conflict/unknown
    ;

golfe

  • preg_replace primeiro: -8 bytes
  • join: -2
  • $$kem vez de $t[$k]: -5
Titus
fonte
1

PHP, 200 + 8 bytes

inspirado na solução Arnaulds .

for($s=join($argv);$c=ord($s[$i++]);$i+=$x)$t[]=$c>90?63:15&($c<65?$c:($c-($c>80)-($c>87)-59)/3)|16*$x="?"==$s[$i];for(;$p++<10;)echo chr(($e=$t[$p]^$d=$t[$p+10])&48|!(15&$e)?min($t[$p],$d)&15|48:63);

recebe entrada de argumentos de linha de comando; correr com -nrou experimentar online .

modificações para cumprir a restrição de saída de erro: (impressãoX para um número incompleto):

  • retirar |48 (-3 bytes)
  • substituir echo chr(...);por $r.=...;echo$r>1e10?X:$r;(+11 bytes)

demolir

for($s=join($argv);$c=ord($s[$i++]);    # loop through characters of arguments
    $i+=$x)                             # skip "?"
$t[]=
    $c>90                               # if "_"
        ?63                             # then 32+16+15
        :                               # else
            15&(                            # lower 4 bits of
            $c<65                               # if digit
            ?$c                                 # then digit
            :($c-($c>80)-($c>87)-59)/3          # else letter mapped to digit
        )
        |16*$x="?"==$s[$i]                  # if next char is "?", add 16
;
for(;$p++<10;)echo chr( # loop through translated arguments
    (
        $e=$t[$p]^      # 2. $e=difference
        $d=$t[$p+10]    # 1. $d=char from 2nd argument
    )&48                # if certainties differ
    |!(15&$e)           #    or digits do not
    ?min($t[$p],$d)&15|48   # then pick the more definite digit (15|48 -> "?")
    :63             # else "?"
);

golfe

  • Gambiarra preg_replace_callback (-10 bytes)
  • confie na entrada de 10 dígitos (-9)
  • e golfe adicional (-8)
  • removido joindelimitador (-7)
  • $xtarefa movida para o final (-2)
Titus
fonte
1

Perl 5 -pl , 173 bytes

sub t{$_=pop;y/A-Z/22233344455566677778889999/;/_|\d\??/g}@e=m|\S+|g;@a=t$e[0];$_=join"",map{$_.=shift@a;s/^(.+)\1$/$1/||s/_//||s/..../_/||s/.\?//;$_}t$e[2];s/\?//;$_ x=!/_/

Experimente online!

Xcali
fonte