Intercambio de una letra

18

El foro más grande en la web, llamado postcount ++, decidió crear un nuevo juego de foro. En este juego, el objetivo es publicar la palabra, pero la palabra debe tener una letra agregada, eliminada o modificada. Tu jefe quería que escribieras un programa que corriera la voz y el diccionario UNIX, mientras trabajas para una empresa que tiene un foro más inteligente con juegos de foro más inteligentes y quiere destruir a la competencia (oye, es tu jefe, no lo hagas). discuta con él, de todos modos obtiene mucho efectivo de su trabajo).

Su programa obtendrá dos argumentos, la palabra y el diccionario. Debido a que el usuario que administra el programa (sí, un usuario, su empresa no tiene recursos para ejecutar bots) no es perfecto, debe normalizar el caso en ambos. Las palabras en el diccionario pueden tener letras ASCII (mayúsculas y minúsculas, pero deben ignorarse durante la comparación), guiones, apóstrofes y espacios no consecutivos en el medio. No tendrán más de 78 caracteres. Tienes que generar una lista de palabras que serían aceptadas en el juego, para romper la diversión de las personas que piensan en palabras manualmente.

Este es un ejemplo de su programa esperado, buscando palabras similares a golf.

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

El /usr/share/dict/wordses una lista de palabras, con salto de línea después de cada una. Puede leerlo fácilmente con fgets (), por ejemplo.

La empresa en la que trabaja no tiene muchas tarjetas perforadas (sí, es 2014, y todavía usan tarjetas perforadas), así que no las desperdicie. Escribe el programa más corto posible. Ah, y se le pidió que no utilizara implementaciones integradas o externas de la distancia de Levenshtein o cualquier algoritmo similar. Algo sobre No inventado aquí o puertas traseras que aparentemente el vendedor insertó en el idioma (no tiene pruebas de eso, pero no discuta con su jefe). Entonces, si desea distancia, deberá implementarla usted mismo.

Eres libre de usar cualquier idioma. Incluso con tarjetas perforadas, la compañía tiene acceso a los lenguajes de programación más modernos, como Cobol Ruby o Haskell o lo que quieras. Incluso tienen GolfScript, si crees que es bueno para la manipulación de cadenas (no sé, tal vez ...).

El ganador obtiene 15 puntos de reputación de mí y probablemente muchos otros puntos de la comunidad. Las otras buenas respuestas obtendrán 10 puntos, y puntos de la comunidad también. Escuchaste que los puntos no valen nada, pero lo más probable es que reemplacen dolares en 2050. Sin embargo, eso no se confirmó, pero es una buena idea obtener puntos de todos modos.

Konrad Borowski
fuente
66
¿No deberíamos "usar implementaciones incorporadas o externas de la distancia de Levenshtein o algún algoritmo similar"? Ahí va la solución de Mathematica de 30 caracteres.
Michael Stern
@MichaelStern y un Python similarmente corto que usa la coincidencia difusa de esta biblioteca de expresiones regulares
Martin Ender
2
Casi lo mismo que codegolf.stackexchange.com/questions/6939/… .
Howard
"como Ruby o Haskell" - ok, lo tengo, quieres que participe.
John Dvorak
Proporcione un mejor ejemplo, para que aparezcan todos los tipos de cambios o las personas sigan enviando algoritmos incorrectos.
swish

Respuestas:

4

GolfScript, 59 caracteres

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

¡Claro, GolfScript es ideal para la manipulación de cadenas!

Lo que GolfScript no es tan bueno es manejar E / S de archivos o argumentos de línea de comandos. Por lo tanto, este programa espera recibir toda su entrada a través de stdin: la primera línea no en blanco se considera la palabra objetivo, mientras que las líneas restantes deben contener el diccionario. En un sistema Unixish, puede ejecutar este código, por ejemplo, con:

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

En mi cuadro Ubuntu Linux, el resultado del comando anterior es:

goff
wolf
gold
golfs
goof
gulf

Tenga en cuenta que todas las palabras se convierten en minúsculas y se eliminan los duplicados; por lo tanto, a diferencia de su salida de muestra, la mía no aparece en la lista Wolfy por wolfseparado. Según la descripción de su desafío, supongo que esto es aceptable.

Además, el código es realmente lento, ya que utiliza un enfoque de fuerza bruta y ni siquiera utiliza optimizaciones obvias, como verificar que la longitud de la palabra candidata coincida con la de la palabra objetivo ± 1. Aún así, se las arregla para ir a través de la /usr/share/dict/wordslista completa, sin filtrar en ... um ... Te avisaré cuando termine, ¿de acuerdo?

Editar: OK, tardó unos 25 minutos, pero terminó.

Ilmari Karonen
fuente
+1 para una representación precisa de lo bueno que es GolfScript para la manipulación de cadenas (y hacer la manipulación de cadenas en GolfScript)
PlasmaPower
6

Bash + coreutils, 99 bytes

O bien entendí mal la pregunta ( la respuesta de @ lambruscoAcido da resultados muy diferentes ), o esta es una aplicación de expresiones regulares bastante sencilla:

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

Salida:

$ ./similar.sh golf / usr / share / dict / words
Goff
oro
golf
campos de golf
bobo
Golfo
lobo
Lobo
PS 
Trauma digital
fuente
¿Puedes explicar qué ${a:b:c} hacer?
AL
1
@ n.1 toma los caracteres en las posiciones bde cla variablea
2
@professorfish Close: es la subcadena de longitud que ccomienza en la posición b(basada en cero) de la variable a. La expansión de subcadenas es una de las expansiones de parámetros bash
Digital Trauma
2
@DigitalTrauma oh, lo olvidé a pesar de que sigo usándolo en mis campos de golf Bash
3

Python 3, 291 caracteres

Muy sencillo y, por lo tanto, no muy inteligente. Pero con una gran maraña de generador y lentitud optimizada. Porque no quiere dejar el tiempo de cálculo asignado sin usar, ¿verdad?

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
fuente
1
Puede usar l=leny r=rangereducir esas funciones aún más.
TyrantWave
1

Scala - 403 130

[Actualizado]: completamente actualizado porque la solución anterior también permitía letras permutadas. No utiliza expresiones regulares ni ninguna herramienta integrada.

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

Sin golf:

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
fuente
@ DigitalTrauma ¿Puede darme un ejemplo para ese problema?
lambruscoAcido
Lo entendí: también consideré todas las permutaciones de las letras. Suspiro, entonces la realidad es más fácil. Gracias ...
lambruscoAcido
atechnyNo cambia una letra. Esta solución hace algo no relacionado con la pregunta.
Konrad Borowski
+1. parece que ahora se ajusta mejor a las especificaciones ;-)
Digital Trauma
Un programa completo sería bueno, no solo la función.
swish
1

Python, 174 caracteres:

Rápido y al punto.

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})

Ejemplo:

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

Salida:

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

Supongo que el archivo de palabras OS X solo tiene más entradas.

xleviator
fuente
La lista no debe incluir la palabra misma y tampoco ignora los apóstrofes: con el diccionario UNIX también lo tiene golf'.
swish
¿Qué quieres decir con ignorar los apóstrofes? Después de volver a leer el mensaje, todavía no veo a qué te refieres.
xleviator
Si ejecuto su código en el diccionario golf', se imprimirá.
swish
Ah, había leído mal el mensaje, pero ya está solucionado.
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
silbido
fuente
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]]


Sin golf (con algunos comentarios):

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]
]

Ejemplo de uso (probado en Rebol 3 en 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

A continuación se muestra la parseregla creada para que coincida con palabras similares a golf :

[
    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
fuente
-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, creo. Además, me gusta lo bien que esto jugó en Python.

ɐɔıʇǝɥʇuʎs
fuente
No tiene en cuenta la eliminación o la adición de un personaje.
swish