一字母互换


18

网络上最大的论坛postpost ++决定制作一个新的论坛游戏。在此游戏中,目标是发布单词,但是单词必须添加,删除或更改一个字母。您的老板希望您编写一个程序来获取单词,并使用UNIX词典,因为您在一家拥有更智能论坛和更智能论坛游戏的公司工作,并想破坏竞争(嘿,这是您的老板,不要与他讨论,无论如何您都会从工作中获得很多现金)。

您的程序将获得两个参数,单词和字典。由于管理程序的用户(是的,用户,您的公司没有资源来运行机器人)并不完美,因此您应该对两种情况都进行规范化处理。词典中的单词可能具有ASCII字母(大写和小写,但在比较时应将其忽略),破折号,撇号和中间的非连续空格。它们不能超过78个字符。您必须输出游戏中可以接受的单词列表,以打破手动思考单词的人们的乐趣。

这是您期望的程序的示例,检查与相似的词golf

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

/usr/share/dict/words是单词的列表,每个后换行符。例如,您可以使用fgets()轻松阅读该内容。

您工作的公司没有很多打孔卡(是的,这是2014年,他们仍然使用打孔卡),所以请不要浪费它们。编写尽可能短的程序。哦,您被要求不要使用Levenshtein距离的内置或外部实现或任何类似算法。关于“此处未发明”或显然是供应商插入该语言的后门的东西(您没有这些的证明,但不与老板讨论)。因此,如果您需要距离,则必须自己实现。

您可以自由使用任何语言。即使有了打孔卡,该公司也可以使用最现代的编程语言,例如Cobol Ruby或Haskell或任何您想要的东西。他们甚至拥有GolfScript,如果您认为它对字符串操作很有用(我不知道,也许...)。

获胜者会从我那里获得15个声誉点,并可能从社区中获得许多其他积分。其他好的答案将获得10分,社区也将获得分。您听说积分不值钱,但是很有可能在2050年取代美元。但是,这还没有得到证实,但是无论如何要获得积分是一个好主意。


6
我们不应该“使用Levenshtein距离的内置或外部实现或任何类似算法”?有30个字符的Mathematica解决方案。
Michael Stern

@MichaelStern和一个类似的短python使用此正则表达式库
Martin Ender


“例如Ruby或Haskell”-好的,我明白了,您要我参加。
约翰·德沃夏克

请提供一个更好的示例,以便出现所有类型的更改,否则人们将继续提交错误的算法。
沙沙

Answers:


4

GolfScript,59个字符

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

当然,GolfScript 非常适合字符串操作!

GolfScript 不太擅长的是处理文件I / O或命令行参数。因此,该程序希望通过stdin接收其所有输入:第一条非空白行被视为目标单词,而其余行应包含字典。在Unixish系统上,您可以运行以下代码,例如:

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

在我的Ubuntu Linux机器上,以上命令的输出为:

goff
wolf
gold
golfs
goof
gulf

请注意,所有单词都转换为小写,并且所有重复项都被消除;因此,与您的样本输出,矿井未列出Wolfwolf分别。根据您的挑战描述,我认为这是可以接受的。

而且,代码确实很慢,因为它使用了蛮力的方法,甚至没有使用明显的优化,例如检查候选单词的长度是否与目标单词的长度±1相匹配。通过...的完整,未经过滤的/usr/share/dict/words列表...嗯,等它结束时,我会通知您,好吗?

编辑:好的,大约花了25分钟,但是确实完成了。


+1可以准确表示GolfScript在字符串处理方面的优良表现(并在GolfScript中进行字符串处理)
PlasmaPower 2014年

6

Bash + coreutils,99个字节

我完全误解了这个问题(@lambruscoAcido的答案给出了截然不同的结果),或者这是一个相当简单的regexp应用程序:

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

输出:

$ ./like.sh golf / usr / share / dict / words
高夫
金
高尔夫球
高尔夫
傻瓜
海湾
狼
狼
$ 

你能解释一下${a:b:c} 吗?
AL

1
@ n.1,它将变量中位置处的字符b移至ca

2
@professorfish Close- 从变量的c位置b(从零开始)开始的长度子字符串a。子字符串扩展是bash参数扩展之一
Digital Trauma 2014年

2
@DigitalTrauma哦,即使我在Bash高尔夫中继续使用它,我也忘记了

3

Python 3,291个字符

非常简单,因此不是很聪明。但是带有大量美味的发电机缠结和优化的慢度。因为您不想不使用分配的计算时间,所以吗?

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

1
可以使用l=lenr=range进一步减少那些功能。
TyrantWave

1

斯卡拉- 403 130

[更新]:完全更新,因为以前的解决方案还允许排列字母。不使用正则表达式或任何内置工具。

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

取消高尔夫:

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
}

用法:

f("golf", io.Source.fromFile("/usr/share/dict/words").getLines.toList)

@DigitalTrauma您能举个例子说明这个问题吗?
lambruscoAcido

我明白了:我还考虑了字母的所有排列。叹气-这样现实就容易多了。谢谢...
lambruscoAcido14年

atechny不会改变一个字母。此解决方案所做的事情与问题无关。
Konrad Borowski14年

+1。看起来现在更符合规格了;-)
Digital Trauma

一个完整的程序会很好,而不仅仅是功能。
2014年

1

Python,174个字符:

快速而切入点。

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

例:

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

输出:

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

我想OS X的word文件只有更多条目。


List不应该包含单词本身,也不应该忽略撇号:对于UNIX词典,它也应该包含golf'
沙沙

忽略撇号是什么意思?重新阅读提示后,我仍然看不到您的意思。
xleviator

如果我在其中的字典上运行您的代码golf',它将被打印出来。
swish 2014年

啊,我看错了提示,但是现在已经解决了。
xleviator

0

哈斯克尔-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

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


取消高尔夫(有一些评论):

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

用法示例(在OS X Lion的Rebol 3中测试):

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

以下是为将parse类似单词匹配到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"
]

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

我认为效率很高。另外,我喜欢它在Python中打的好。


您无需考虑删除或添加字符。
swish
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.