Crie um teclado T9

12

Esta pergunta solicita uma funcionalidade de correspondência de dicionário T9, que é um problema muito interessante. Mas o T9 tem outra maneira de digitar, que é digitar caractere por caractere. Você NÃO precisaria de um dicionário para implementar este teclado.

Aqui está o mapa de teclas de um teclado T9 se você esqueceu:

+-------+-------+-------+
|   1   |   2   |   3   |
|  .?!  |  ABC  |  DEF  |
+-------+-------+-------+
|   4   |   5   |   6   |
|  GHI  |  JKL  |  MNO  |
+-------+-------+-------+
|   7   |   8   |   9   |
| PQRS  |  TUV  |  WXYZ |
+-------+-------+-------+
|   *   |   0   |   #   |
|   ←   | SPACE |   →   |
+-------+-------+-------+

Como o T9 funciona

Para digitar um caractere com T9, você precisa pressionar a tecla numérica que representa esse ntempo. né a ordem desse caractere escrito nessa chave. Os números são o último caractere que você pode digitar para cada tecla. Por exemplo, para digitar Beu pressione 2duas vezes ou para digitar 5eu pressione 5quatro vezes. Para terminar de digitar esse caractere, pressione #. *é simplesmente backspace. Em nossa versão do teclado, não há letras maiúsculas.

Exemplos de entrada e saída:

8#99999#055#33#999#22#666#2#777#3# → T9 KEYBOARD

Explicação:

  • 8seleciona Te #move para o próximo caractere
  • 99999selecione o último caractere da 9chave que é 9e #move para o próximo caractere
  • 0 insere um espaço
  • 33seleciona o segundo caractere da 3tecla que é Ke #passa para o próximo caractere
  • E assim por diante...

Regras

Sua função ou programa deve aceitar uma sequência que representa as teclas pressionadas T9. Saída é o texto resultante dessas teclas, conforme descrito acima.

Este é um código básico de golfe, portanto o vencedor é o mais curto em bytes, e aplicam-se regras / brechas padrão.

Mohsen
fonte
Bônus não tem nenhum efeito na pontuação? Por que eu iria fazer isso?
Optimizer
2
Além disso, seu exemplo T9 KEYBOARDestá completamente errado. Aquele lêT9 JEYBARD
Otimizador
1
@Mohsen geralmente, os bônus no código de golfe subtraem uma quantia fixa da pontuação. você terá que descobrir quanto é razoável. para o primeiro bônus provavelmente não mais que 10 ou 20 bytes. o segundo bônus, eu nem entendo. se eu der a sequência de pressionamentos de tecla como uma string para a função, como haveria algum tipo de tempo entre os pressionamentos de tecla? Eu acho que um bônus mais razoável seria permitir a omissão #se os botões consecutivos forem diferentes de qualquer maneira. o que foi dito: sem esse bônus, o que aconteceria se #for omitido?
Martin Ender
1
Você precisa adicionar um possível benefício de contagem de bytes para esses bônus. Os bônus são opcionais, mas você parece pedir todas as respostas para implementá-los como se fossem obrigatórios. Limpe o tom, se for obrigatório, mova-o para as regras; se não for, não peça todas as respostas para implementar os bônus. Aguardarei algumas horas pela sua resposta antes de encerrar a votação como pouco claro.
Optimizer
2
Nenhuma resposta, mesmo após 18 horas. A votação para fechar não está clara.
Optimizer

Respostas:

5

CJam, 109 94 bytes ( bônus)

Uma solução muito ingênua e longa

q'#/);{__'*-:A-,_g{){;}*A_}*;'0/{_,g{)~".?~1"a'[,65>292994 5b{/(X):X+\s}%+1:Xm>=\,=}*}%S*1/~}%

Este é um programa completo, embora uma função tenha a mesma duração.

A entrada entra em STDIN

Exemplo:

8#99999#055#33#999#***22#666#2#777#3#

Resultado:

T9 BOARD

Experimente online aqui

Optimizer
fonte
Você pode fazê-lo funcionar pelo primeiro bônus?
Mohsen
3
@ Ohhsen Não até que haja um benefício real de ir para o bônus! Digamos, uma redução de 25% no comprimento do código na pontuação final.
Optimizer
2

JavaScript ES6, 220-10 = 210 178 bytes

Como parte do CMC de Helka , superei meu primeiro desafio.

n=>(g=n=>n==(k=n.replace(/.\*/,""))?n:g(k))(n.match(/(\d)\1*|\*/g).map(e=>e<"0"?e:(a=" |.?!|ABC|DEF|GHI|JKL|MNO|PQRS|TUV|WXYZ".split`|`[+e[0]]+e[0])[~-e.length%a.length]).join``)

Saídas de amostra:

> f=n=>(g=n=>n==(k=n.replace(/.\*/,""))?n:g(k))(n.match(/(\d)\1*|\*/g).map(e=>e<"0"?e:(a=" |.?!|ABC|DEF|GHI|JKL|MNO|PQRS|TUV|WXYZ".split`|`[+e[0]]+e[0])[~-e.length%a.length]).join``)
[Function]
> f("8#99999#055#33#999#***22#666#2#777#3#")
'T9 BOARD'
> f("8#44#33#0#999#*77#88#444#222#55#0#22#777#666#9#66#0#333#666#99#0#5#88#6#7#7777#0#666#888#33#777#0#8#44#33#0#555#2#99#*9999#999#0#3#666#4#111#")
'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG!'
> f("8#99999#055#33#999#***22#666#2#777#3#")
'T9 BOARD'

Explicação

(g=n=>n==(k=n.replace(/.\*/,""))?n:g(k))

Isso implementa a substituição recursiva, substituindo todos os caracteres seguidos por *até que não haja mais *s.

n.match(/(\d)\1*|\*/g)

Isso corresponde a todas as execuções de dígitos consecutivos ou *s.

a=" |.?!|ABC|DEF|GHI|JKL|MNO|PQRS|TUV|WXYZ".split`|`[+e[0]]+e[0]

Isso cria o dicionário desejado, obtendo a parte codificada da cadeia grande e anexando o dígito desejado a ela.

a[~-e.length%a.length]

Isso pega o personagem, ao comprimento do módulo .

.join``

Isso prepara a cadeia de caracteres para processamento e remoção de *s.

Conor O'Brien
fonte
1
Você pode fazê-lo funcionar com o primeiro bônus?
Mohsen
@ Ohssen Sim, e isso pode realmente ajudar. Vou trabalhar nisso hoje e amanhã.
Conor O'Brien
Pelo menos, não anuncie uma pontuação incorreta, pois a resposta não está de acordo com as especificações.
Optimizer
@Mohsen Agora está trabalhando com o primeiro bônus.
Conor O'Brien
t("2#2");dá em Bvez de AA. Tente combinar qualquer um em #vez de removê-los.
Titus
1

Python, 167 157 151 bytes

(não suporta '*')

Nada especial. Uso regex para converter a entrada em uma lista e, em seguida, faço um loop nas entradas. Eu uso o primeiro caractere e o comprimento de cada entrada para pesquisá-lo em uma lista de pesquisa:

def f(i):
  import re
  t9 = [" 0",".?!1","ABC2","DEF3","GHI4","JKL5","MNO6","PQRS7","TUV9","WXYZ9"]
  i = re.findall(r'[1-9]+|0+',i)
  answer = []
  for j in i:
    answer = answer + [t9[int(j[0])][len(j)-1]]
  return ''.join(answer)

Depois de jogar golfe, fica assim:

import re;m=lambda i:"".join([" 0,.?!1,ABC2,DEF3,GHI4,JKL5,MNO6,PQRS7,TUV9,WXYZ9".split(",")[int(j[0])][len(j)-1] for j in re.findall(r'[1-9]+|0+',i)])

Nenhum bônus (ainda). Não sei como implementaria o primeiro bônus no regex. O segundo bônus adicionaria muitos bytes, pois os elementos de pesquisa não são do mesmo tamanho. Realmente não entendo o terceiro bônus.

Def
fonte
1

Perl 5: 106 (código 104 + 2 sinalizadores)

Modificado para lidar com exclusões.

#!perl -lp
s/((\d)\2*)#?|./chr$2*5+length$1/ge;y//d 0-3.?!1 ABC2 DEF3 GHI4 JKL5 MNO6 P-S7TUV8 W-Z9/c;1while s/.?d//

Uso:

perl t9.pl <<<'8#99999#055#33#999#22#666#2#777#3#'
perl t9.pl <<<'899999055339992266627773'

Perl 5: 88 (código 86 + 2 sinalizadores)

Versão antiga sem excluir com estrela.

#!perl -lp
s/(\d)(\1*)#?/chr$1*5+length$2/ge;y// 0-3.?!1 ABC2 DEF3 GHI4 JKL5 MNO6 P-S7TUV8 W-Z9/c
nutki
fonte
O @Optimizer tentou e, de fato, não funciona com *. É realmente necessário? Ele diz: "Observe que ele pode incluir * para backspace ..."
Def
Uma vez que não faz parte do bônus. É uma regra obrigatória.
Optimizer
Dito isto. a questão não é clara sobre o que é uma regra e o que é um bônus. Pedi esclarecimentos à OP há várias horas. Se não houver resposta, estou votando para encerrar esta questão como pouco clara.
Optimizer
Desculpe, fui enganado, pois as respostas atuais nos idiomas que posso ler também não são compatíveis com *.
nutki
Se você está se referindo à minha resposta em python, está certo. Eu interpretei mal a pergunta.
Def
1

AWK 211 bytes (com os bônus)

{split(".?!1-ABC2-DEF3-GHI4-JKL5-MNO6-PQRS7-TUV8-WXYZ9- 0",k,"-");split($0"#",a,"");while(1+(b=a[++i])){if(b==p)++c;else{for(g in k)if(p==substr(k[g],l=length(k[g])))printf(substr(k[g],1+((c-1)%l),1));c=1;p=b}}}

Este é um programa completo que lê a entrada do stdin. Seria mais eficiente não reposicionar o teclado para cada linha, mas tornaria o script mais longo.

Além disso, se a chave "0" fosse qualquer coisa além de 0, o script seria 4 bytes mais curto, mas isso faz parte do jogo: o)

LeFauve
fonte
1

C (245 bytes)

#define M "8#44#33#0#999#*77#88#444#222#55#0#22#777#666#9#66#0#333#666#99#0#5#88#6#7#7777#0#666#888#33#777#0#8#44#33#0#555#2#99#*9999#999#0#3#666#4#111#"

#include<stdio.h>
char K[][4]={" ",".?!","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"},I[]=M;int       
i,j,k,r;main(){for(;I[i];++i){if(I[i]=='#')I[j++]=K[k][--r],r=k=0;else               
if(I[i]=='*')j?--j:0;else if(!r++)k=I[i]-'0';}I[j]=0;printf("%s\n",I);}

Resultado

THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG!

Explicação

A contagem de bytes não inclui a sequência de entrada fornecida no primeiro #define.

Eu uso uma matriz bidimensional como tabela de pesquisa para qual caractere imprimir. O programa lê caracteres delimitados por '#'.

Para cada grupo, o número de entrada determina o índice da matriz de primeira dimensão e o número de repetições do número de entrada determina o índice da matriz de segunda dimensão. Os '*'move para trás o índice da matriz para a cadeia de saída, de modo a substituir a letra anterior.

Portanto, a sequência de entrada 44#(1 repetição de '4') é traduzida para a tabela de pesquisa K[4][1], que é o caractere H.


Versão Ungolfed

#define INPUT "8#44#33#0#999#*77#88#444#222#55#0#22#777#666#9#66#0#333#666#99#0#5#88#6#7#7777#0#666#888#33#777#0#8#44#33#0#555#2#99#*9999#999#0#3#666#4#"

#include<stdio.h>

static const char keyboard[10][4] = {" ", ".?!", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"};

int main(void)
{
  char input[] = INPUT;
  char output[256];
  int i, j;
  int key = 0;
  int reps = 0;

  for (i = j = 0; input[i] != '\0'; ++i) {
    switch (input[i]) {
    case '#':
      output[j] = keyboard[key][reps - 1];
      ++j;
      reps = key = 0;
      break;
    case '*':
      if (j > 0) --j;
      break;
    default:
      if (reps == 0)  {
        key = (int)input[i] - '0';
      }
      ++reps;
      break;
    }
  }

  output[j] = '\0';
  printf("%s\n", output);

  return(0);
}
musaritmia
fonte
1

Rubi 254 , 248 , 229 bytes

Golfe:

n=->(t){r,m,b=[]," _.?!1_ABC2_DEF3_GHI4_JKL5_MNO6_PQRS7_TUV8_WXYZ9_*_0_#".split("_"),nil;t.scan(/((.)\2*)/){|l,_|(!(l=~/\#/)?(l=~/\*/?(r.pop l.size):(l=="00"?r<<(b ? "0 ":" 0"):(c=m[l[0].to_i];r<<c[l.size%c.size-1]))):b=l)};r*""}

Ungolfed:

def t9totext(t)
  bonq = nil
  numpad = [" ",".?!1","ABC2","DEF3","GHI4","JKL5","MNO6","PQRS7","TUV8","WXYZ9","*","0","#"]

  r = []
  t.scan(/((.)\2*)/) do |l, _|
    if !(l =~ /\#/)
      if l =~ /\*/
        r.pop(l.size)
      elsif l == "00"
        r << (bonq ? "0 " : " 0")
      else
        c = numpad[l[0].to_i]
        r << c[l.size % c.size - 1]
      end
    else
      bonq = l
    end
  end
  r.join
end

Todas essas especificações devem ter sucesso:

  it "outputs the correct word" do
    expect(n.call('8#99999#055#33#999#22#666#2#777#3#1')).to eq("T9 KEYBOARD.")
    expect(n.call('4433555#55566609666666677755533*3111')).to eq("HELLO WORLD!")
    expect(n.call('7##222#222**7#222#4')).to eq('PPCG')
    expect(n.call('00#0#00')).to eq(' 0 0 ')
  end

A 0 0resposta parece um pouco com uma solução hacky. Vou investigar quando tiver tempo.

Biketire
fonte
0

PHP, 183-10 = 173 bytes

Todas as versões pegar as informações de linha de comando argumento; call com php -r '<code>' <string>.

Nota : Todas as versões emitem um aviso se a entrada começar com *.
Anexar $o=[];ao código para remover essa falha.

preg_match_all("%(\d)\1*|\*%",$argv[1],$m);foreach($m[0]as$w)if("*"==$w)array_pop($o);else$o[]="- 0   .?!1 ABC2 DEF3 GHI4 JKL5 MNO6 PQRS7TUV8 WXYZ9"[$w[0]*5+strlen($w)];echo join($o);
  • não precisa de tags de hash
  • falha se uma tecla for pressionada com muita frequência

210-10 - ?? = ??? bytes

$a=[" 0",".?!1",ABC2,DEF3,GHI4,JKL5,MNO6,PQRS7,TUV8,WXYZ9];preg_match_all("%(\d)\1*|\*%",$argv[1],$m);foreach($m[0]as$w)if("*"==$w)array_pop($o);else$o[]=$a[$w[0]][strlen($w)%strlen($a[$w[0]])-1];echo join($o);
  • não precisa de tags de hash
  • gira se uma tecla for pressionada com muita frequência

181 bytes, sem bônus

preg_match_all("%\d+#|\*%",$argv[1],$m);foreach($m[0]as$w)if("*"==$w)array_pop($o);else$o[]=" 0   .?!1 ABC2 DEF3 GHI4 JKL5 MNO6 PQRS7TUV8 WXYZ9"[$w[0]*5+strlen($w)-2];echo join($o);

demolir

As versões "sem hash tags" dividem a string em (sequência de números iguais) e (asterisco) e esquecem todo o resto. A versão sem bônus leva (sequência de números seguida por #) e (asterisco).

Em seguida, percorra as correspondências: Se um '*' for encontrado, remova o último elemento da matriz de resultados.

A diferença entre as versões está na elseparte:

  • sem versão bônus: desloque a sequência do mapa para (tecla * 5) e adicione (pressionamentos de tecla = comprimento da palavra-1) -1, adicione o caractere dessa posição ao resultado.
  • versão simples sem etiqueta: quase a mesma, mas: (pressionamentos de tecla = comprimento da palavra); adicionou um caractere à sequência do mapa para se livrar do outro -1.
  • versão rotativa: pegue o item (chave) da matriz do mapa, adicione o caractere (pressionamentos de teclas% item comprimento-1) desse item ao resultado.
Titus
fonte
0

JavaScript, 147 bytes

A resposta de Conor foi corrigida com o regex da minha resposta PHP e diminuiu.

t=i=>i.match(/(\d)\1*|\*/g).map(w=>(" 0~.?!1~ABC2~DEF3~GHI4~JKL5~MNO6~PQRS7~TUV8~WXYZ9".split`~`[w[0]]||"*")[w.length-1]).join``.replace(/.\*/g,"")

demolir

t=i=>i
    .match(/(\d)\1*|\*/g)   // split input to streaks of equal numbers and single `*`
    .map(w=>                // replace each item with ...
                            // .. take string depending on the digit
        (" 0~.?!1~ABC2~DEF3~GHI4~JKL5~MNO6~PQRS7~TUV8~WXYZ9".split`~`[w[0]]
        ||"*")              // .. ("*" for not a digit)
        [w.length-1]        // -> the (item length)th character of that string
    )
    .join``                 // join without delimiter
    .replace(/.\*/g,"")     // and recursively remove every (letter,asterisk) combination

versão rotativa, 158 bytes

adicionado s=para lembrar a corda e %s.lengthgirar.

t=i=>i.match(/(\d)\1*|\*/g).map(w=>(s=" 0~.?!1~ABC2~DEF3~GHI4~JKL5~MNO6~PQRS7~TUV8~WXYZ9".split`~`[w[0]]||"*")[w.length%s.length-1]).join``.replace(/.\*/g,"")
Titus
fonte