Troca de uma letra

18

O maior fórum da web, chamado pós-contagem ++, decidiu criar um novo jogo no fórum. Neste jogo, o objetivo é postar a palavra, mas a palavra precisa ter uma letra adicionada, removida ou alterada. Seu chefe queria que você escrevesse um programa que recebesse a palavra e o dicionário UNIX, enquanto trabalha para uma empresa que possui um fórum mais inteligente com jogos mais inteligentes e deseja destruir a concorrência (ei, é seu chefe, não discuta com ele, você recebe muito dinheiro do seu trabalho).

Seu programa receberá dois argumentos, a palavra e o dicionário. Como o usuário que gerencia o programa (sim, um usuário, sua empresa não possui recursos para executar bots) não é perfeito, você deve normalizar o caso em ambos. As palavras no dicionário podem ter letras ASCII (maiúsculas e minúsculas, mas devem ser ignoradas durante a comparação), traços, apóstrofes e espaços não consecutivos no meio. Eles não terão mais de 78 caracteres. Você precisa produzir uma lista de palavras que seriam aceitas no jogo, para acabar com a diversão das pessoas que pensam nas palavras manualmente.

Este é um exemplo do seu programa esperado, verificando palavras semelhantes a golf.

> ./similar golf /usr/share/dict/words
Goff
Wolf
gold
golfs
goof
gulf
wolf

A /usr/share/dict/wordsé uma lista de palavras, com quebra de linha após cada uma. Você pode ler isso facilmente com fgets (), por exemplo.

A empresa em que você trabalha não possui muitos cartões perfurados (sim, é 2014 e eles ainda usam cartões perfurados), portanto, não os desperdice. Escreva o programa mais curto possível. Ah, e você foi solicitado a não usar implementações internas ou externas da distância de Levenshtein ou qualquer algoritmo semelhante. Algo sobre Não inventado aqui ou backdoors que aparentemente o fornecedor inseriu no idioma (você não tem provas disso, mas não discute com seu chefe). Portanto, se você quiser distância, terá que implementá-la você mesmo.

Você é livre para usar qualquer idioma. Mesmo com cartões perfurados, a empresa tem acesso às mais modernas linguagens de programação, como Cobol Ruby ou Haskell ou o que você quiser. Eles até têm GolfScript, se você acha que é bom para manipulação de strings (talvez eu não saiba ...).

O vencedor recebe 15 pontos de reputação de mim e provavelmente muitos outros pontos da comunidade. As outras boas respostas receberão 10 pontos e pontos da comunidade também. Você ouviu dizer que os pontos são inúteis, mas provavelmente substituirá os dólares em 2050. No entanto, isso não foi confirmado, mas é uma boa ideia obter pontos de qualquer maneira.

Konrad Borowski
fonte
6
Não devemos "usar implementações internas ou externas da distância de Levenshtein ou qualquer algoritmo semelhante"? Lá está a solução Mathematica de 30 caracteres.
Michael Stern
@MichaelStern e um igualmente curto python usando a correspondência difusa de esta biblioteca regex
Martin Ender
2
Quase o mesmo que codegolf.stackexchange.com/questions/6939/… .
Howard
"como Ruby ou Haskell" - ok, entendi, você quer que eu participe.
21415 John Dvorak
Forneça um exemplo melhor, para que todos os tipos de alterações apareçam ou as pessoas continuem enviando algoritmos errados.
abanada

Respostas:

4

GolfScript, 59 caracteres

{32|}%"*"%.|(:w;{:x,),{:^[x>.1>]{.[^w=]\+}%{^x<\+w=},},},n*

Claro, o GolfScript é ótimo para manipulação de strings!

O que o GolfScript não é tão bom é lidar com E / S de arquivo ou com argumentos de linha de comando. Portanto, este programa espera receber toda a sua entrada via stdin: a primeira linha que não estiver em branco é considerada a palavra de destino, enquanto as linhas restantes devem conter o dicionário. Em um sistema Unixish, você pode executar este código, por exemplo, com:

(echo golf; cat /usr/share/dict/words) | ruby golfscript.rb similar.gs

Na minha caixa do Ubuntu Linux, a saída do comando acima é:

goff
wolf
gold
golfs
goof
gulf

Observe que todas as palavras são convertidas em minúsculas e as duplicatas são eliminadas; portanto, diferente da sua saída de amostra, a minha não lista Wolfe wolfseparadamente. Com base na descrição do seu desafio, presumo que isso seja aceitável.

Além disso, o código é realmente lento, pois usa uma abordagem de força bastante bruta e não usa otimizações óbvias, como verificar se o comprimento da palavra candidata corresponde ao da palavra-alvo ± 1. Ainda assim, ele consegue ir através da /usr/share/dict/wordslista completa, não filtrada, em ... um ... Eu avisarei quando terminar, ok?

Edit: OK, demorou cerca de 25 minutos, mas terminou.

Ilmari Karonen
fonte
+1 para uma representação precisa de como bom GolfScript é para manipulação de strings (e fazendo a manipulação de cadeia no GolfScript)
PlasmaPower
6

Bash + coreutils, 99 bytes

Ou eu entendi totalmente a pergunta ( a resposta de @ lambruscoAcido fornece resultados muito diferentes ) ou esta é uma aplicação regexp bastante direta:

for((i=0;i<${#1};i++)){
a=${1:0:i}
b=${1:i+1}
egrep -i "^($a$b|$a.$b|$a.${1:i}|$1.)$" $2
}|sort -u

Resultado:

$ ./similar.sh golf / usr / share / dict / words
Goff
ouro
golfe
golfs
brincadeira
golfo
Lobo
Lobo
$ 
Trauma Digital
fonte
Você pode, por favor, explicar o que ${a:b:c} fazer?
AL
1
@ n.1 leva os caracteres nas posições bpara ca variávela
2
@professorfish Close - é a substring do comprimento ccomeçando na posição b(com base em zero) da variável a. A expansão de substring é um dos expansões de parâmetro bash
Digital Trauma
2
@DigitalTrauma oh esqueci mesmo que eu continuo usando-o nos meus Bash golfs
3

Python 3, 291 caracteres

Muito simples e, portanto, não muito inteligente. Mas com um emaranhado gostoso de gerador e lentidão otimizada. Como você não deseja deixar o tempo de computação alocado sem uso, não é?

from itertools import*
from sys import*
a=argv[1].lower()
r,l=range,len
n=l(a)
print('\n'.join((b for b in(s.strip()for s in open(argv[2]).readlines())if l(b)>n-2and b.lower()in(''.join(compress(a,(i!=j for j in r(n))))for i in r(n))or n==l(b)and sum(1for i in r(n)if a[i]!=b.lower()[i])<2)))
Evpok
fonte
1
Pode usar l=lene r=rangereduzir ainda mais essas funções.
precisa saber é o seguinte
1

Scala - 403 130

[Atualizado]: completamente atualizado porque a solução anterior também permitia letras permutadas. Não usa regex ou nenhuma ferramenta interna.

def f(x:String,d:List[String])={for{y<-d;c=(x zip y filter(t=>t._1!=t._2)length);n=y.length-x.length;if c<2&n==0|c==0&n==1}yield y

Ungolfed:

def f(x:String, d:List[String]) = {
  for {
    y <- d
    c = (x zip y filter (t=>t._1!=t._2) length)  // #letter changes.
    n = y.length-x.length                        // Difference in word length.
    if c<2 & n==0 | c==0 & n==1
  } yield y
}

Uso:

f("golf", io.Source.fromFile("/usr/share/dict/words").getLines.toList)
lambruscoAcido
fonte
@DigitalTrauma Você pode me dar um exemplo para essa questão?
precisa saber é o seguinte
Entendi: eu também considerei todas as permutações das cartas. Suspiro - então a realidade é mais fácil. Obrigado ...
lambruscoAcido
atechnynão muda uma letra. Esta solução faz algo não relacionado à pergunta.
Konrad Borowski
+1. parece que ele se encaixa melhor nas especificações agora ;-) #
Digital Trauma
Um programa completo seria bom, não apenas funcionaria.
abanada
1

Python, 174 caracteres:

Rápido e direto ao ponto.

import re;from sys import*;w=argv[1]
print"\n".join(set(sum([re.findall(r"\b%s%s?[^'\n]?%s\b"%(w[:i],w[i],w[i+1:]),open(argv[2]).read(),re.I)for i in range(len(w))],[]))-{w})

Exemplo:

python similar.py golf /usr/share/dict/words

Resultado:

goof
gola
gulf
gold
gol
gowf
goli
Golo
Gulf
goaf
Wolf
Goll
Rolf
wolf
goff
Gold

Suponho que o arquivo de palavras do OS X tenha apenas mais entradas.

xleviator
fonte
A lista não deve incluir a própria palavra e também não ignora os apóstrofos: com o dicionário UNIX, ele também possui golf'.
abanada
O que você quer dizer com ignorar apóstrofos? Depois de reler o prompt, ainda não vejo o que você está recebendo.
Xleviator
Se eu executar seu código no dicionário golf', ele será impresso.
abanada
Ah, eu tinha interpretado mal o prompt, mas está corrigido agora.
Xleviator
0

Haskell - 219

import System.Environment
import Data.Char
u@(x:a)%w@(y:b)|x==y=a%b|1>0=1+minimum[a%w,u%b,a%b]
x%y=max(length x)$length y
main=do[w,d]<-getArgs;readFile d>>=mapM putStrLn.filter((==1).(%map toLower w).map toLower).words
swish
fonte
0

Rebol - 213

set[i d]split system/script/args" "r:[skip i | i skip]repeat n length? i[append r compose[|(poke s: split i 1 n 'skip s)|(head remove at copy i n)]]foreach w read/lines to-file d[if all[w != i parse w r][print w]]


Ungolfed (com alguns comentários):

set [i d] split system/script/args " "

; build parse rule
r: [skip i | i skip]       ; RULE - one letter added (prefix and postfix)

; sub-rule for each letter in word
repeat n length? i [
    append r compose [
        | (poke s: split i 1 n 'skip s)     ; RULE - letter changed
        | (head remove at copy i n)         ; RULE - letter removed
    ]
]

foreach w read/lines to-file d [
    if all [w != i parse w r] [print w]
]

Exemplo de uso (testado no Rebol 3 no OS X Lion):

$ rebol similar.reb golf /usr/share/dict/words
goaf
goff
gol
gola
Gold
gold
goli
Goll
Golo
goof
gowf
Gulf
gulf
Rolf
Wolf
wolf

Abaixo está a parseregra criada para corresponder a palavras semelhantes ao golfe :

[
    skip "golf"
  | "golf" skip
  | skip "o" "l" "f"
  | "olf"
  | "g" skip "l" "f"
  | "glf"
  | "g" "o" skip "f"
  | "gof"
  | "g" "o" "l" skip
  | "gol"
]
draegtun
fonte
-1

Python (103):

f=lambda x:[a for a in open('/usr/share/dict/words')if len(x)==len(a)&sum(b!=c for b,c in zip(a,x))==1]

Bastante eficiente, eu acho. Além disso, eu gosto de quão bem isso foi no golfe em Python.

ɐɔıʇǝɥʇuʎs
fonte
Você não considera a remoção ou a adição de um personagem.
abanada