Hoán đổi một chữ cái


18

Diễn đàn lớn nhất trên web, được gọi là postcount ++ đã quyết định tạo một trò chơi diễn đàn mới. Trong trò chơi này, mục tiêu là đăng từ, nhưng từ này phải có một chữ cái được thêm, xóa hoặc thay đổi. Sếp của bạn muốn bạn viết một chương trình lấy từ và từ điển UNIX, khi bạn làm việc cho công ty có diễn đàn thông minh hơn với các trò chơi diễn đàn thông minh hơn và muốn phá hủy sự cạnh tranh (hey, đó là ông chủ của bạn, đừng thảo luận với anh ta, dù sao bạn cũng nhận được rất nhiều tiền từ công việc của mình).

Chương trình của bạn sẽ nhận được hai đối số, từ và từ điển. Vì người dùng quản lý chương trình (vâng, người dùng, công ty của bạn không có tài nguyên để chạy bot) không hoàn hảo, bạn nên bình thường hóa trường hợp trong cả hai. Các từ trong từ điển có thể có các chữ cái ASCII (cả chữ hoa và chữ thường, nhưng nên bỏ qua trong khi so sánh), dấu gạch ngang, dấu nháy đơn và khoảng trắng không liên tiếp ở giữa. Chúng sẽ không dài hơn 78 ký tự. Bạn phải đưa ra danh sách các từ sẽ được chấp nhận trong trò chơi, để phá vỡ niềm vui của những người nghĩ về từ đó bằng tay.

Đây là một ví dụ về chương trình dự kiến ​​của bạn, kiểm tra các từ tương tự golf.

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

Đây /usr/share/dict/wordslà một danh sách các từ, với dòng ngắt sau mỗi. Bạn có thể dễ dàng đọc nó với fgets () chẳng hạn.

Công ty bạn làm việc không có nhiều thẻ đục lỗ (vâng, đó là năm 2014 và họ vẫn sử dụng thẻ đục lỗ), vì vậy đừng lãng phí chúng. Viết chương trình càng ngắn càng tốt. Ồ, và bạn được yêu cầu không sử dụng các triển khai bên ngoài hoặc bên ngoài của khoảng cách Levenshtein hoặc bất kỳ thuật toán tương tự nào. Một cái gì đó về Không được phát minh ở đây hoặc các cửa hậu có vẻ như nhà cung cấp chèn vào ngôn ngữ (bạn không có bằng chứng về những điều đó, nhưng đừng thảo luận với sếp của bạn). Vì vậy, nếu bạn muốn khoảng cách, bạn sẽ phải tự thực hiện nó.

Bạn được tự do sử dụng bất kỳ ngôn ngữ. Ngay cả với thẻ đục lỗ, công ty có quyền truy cập vào hầu hết các ngôn ngữ lập trình hiện đại, như Cobol Ruby hoặc Haskell hoặc bất cứ điều gì bạn muốn. Họ thậm chí còn có GolfScript, nếu bạn nghĩ rằng nó tốt cho thao tác chuỗi (tôi không biết, có lẽ ...).

Người chiến thắng nhận được 15 điểm danh tiếng từ tôi và có thể rất nhiều điểm khác từ cộng đồng. Các câu trả lời tốt khác sẽ nhận được 10 điểm và điểm từ cộng đồng. Bạn nghe nói rằng điểm là vô giá trị, nhưng rất có thể là chúng sẽ thay thế các học giả vào năm 2050. Tuy nhiên, điều đó chưa được xác nhận, nhưng dù sao thì cũng nên lấy điểm.


6
Chúng ta không nên "sử dụng các triển khai bên ngoài hoặc khoảng cách Levenshtein tích hợp hoặc bất kỳ thuật toán tương tự nào"? Có giải pháp Mathicala 30 ký tự.
Michael Stern

@MichaelStern và một con trăn ngắn tương tự bằng cách sử dụng kết hợp mờ của thư viện regex này
Martin Ender


"Chẳng hạn như Ruby hoặc Haskell" - ok, tôi đã hiểu rồi, bạn muốn tôi tham gia.
John Dvorak

Vui lòng cung cấp một ví dụ tốt hơn để tất cả các loại thay đổi sẽ xuất hiện hoặc mọi người sẽ tiếp tục gửi thuật toán sai.
swish

Câu trả lời:


4

GolfScript, 59 ký tự

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

Chắc chắn, GolfScript là tuyệt vời cho thao tác chuỗi!

Điều mà GolfScript không giỏi lắm là xử lý tệp I / O hoặc đối số dòng lệnh. Do đó, chương trình này hy vọng sẽ nhận được tất cả đầu vào của nó thông qua stdin: dòng không trống đầu tiên được lấy là từ đích, trong khi các dòng còn lại sẽ chứa từ điển. Trên hệ thống Unixish, bạn có thể chạy mã này, ví dụ:

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

Trên hộp Ubuntu Linux của tôi, đầu ra của lệnh trên là:

goff
wolf
gold
golfs
goof
gulf

Lưu ý rằng tất cả các từ được chuyển đổi thành chữ thường và bất kỳ bản sao nào cũng bị loại bỏ; do đó, không giống như đầu ra mẫu của bạn, của tôi không liệt kê Wolfwolfriêng biệt. Dựa trên mô tả thách thức của bạn, tôi cho rằng điều này là chấp nhận được.

Ngoài ra, mã rất chậm, vì nó sử dụng một cách tiếp cận khá mạnh mẽ và không sử dụng các tối ưu hóa rõ ràng như kiểm tra xem độ dài của từ ứng cử viên có khớp với từ của mục tiêu ± 1. Tuy nhiên, nó vẫn xoay sở để đi thông qua /usr/share/dict/wordsdanh sách đầy đủ, chưa được lọc trong ... ừm ... Tôi sẽ cho bạn biết khi nào nó kết thúc, OK?

Chỉnh sửa: OK, mất khoảng 25 phút, nhưng nó đã hoàn thành.


+1 để thể hiện chính xác mức độ tốt của GolfScript đối với thao tác chuỗi (và thực hiện thao tác chuỗi trong GolfScript)
PlasmaPower

6

Bash + coreutils, 99 byte

Hoặc là tôi hoàn toàn hiểu sai câu hỏi ( câu trả lời của @ lambruscoAcido cho kết quả rất khác nhau ) hoặc đây là một ứng dụng regrec khá đơn giản:

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

Đầu ra:

$ ./similar.sh golf / usr / share / dict / words
Goff
vàng
golf
sân gôn
ngốc
Vịnh
chó sói
chó sói
$ 

Bạn có thể vui lòng giải thích những gì ${a:b:c} làm?
AL

1
@ n.1 phải mất các nhân vật tại các vị trí bđể ctrong biếna

2
@professorfish Đóng - chuỗi con có độ dài cbắt đầu từ vị trí b(dựa trên zero) từ biến a. Mở rộng chuỗi con là một trong những mở rộng tham số bash
Chấn thương kỹ thuật số

2
@DigitalTrauma oh tôi đã quên mặc dù tôi vẫn tiếp tục sử dụng nó trong các sân gôn Bash của mình

3

Python 3, 291 ký tự

Rất đơn giản, và do đó không thông minh. Nhưng với một máy phát điện lớn rối và tối ưu hóa chậm. Bởi vì bạn không muốn để thời gian tính toán được phân bổ của mình không được sử dụng, phải không?

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
Có thể sử dụng l=lenr=rangeđể giảm các chức năng đó hơn nữa.
TyrantWave

1

Scala - 403 130

[Cập nhật]: cập nhật hoàn toàn vì giải pháp cũ cũng cho phép các chữ cái được hoán vị. Không sử dụng regex hoặc bất kỳ công cụ dựng sẵn nào.

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

Ung dung:

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
}

Sử dụng:

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

@DigitalTrauma Bạn có thể cho tôi một ví dụ cho vấn đề đó không?
lambruscoAcido

Tôi đã nhận nó: Tôi cũng đã xem xét tất cả các hoán vị của các chữ cái. Thở dài - vì vậy thực tế dễ dàng hơn. Cảm ơn ...
lambruscoAcido

atechnykhông thay đổi một chữ cái. Giải pháp này làm một cái gì đó không liên quan đến câu hỏi.
Konrad Borowski

+1. có vẻ như nó phù hợp với thông số kỹ thuật hơn bây giờ ;-)
Chấn thương kỹ thuật số

Một chương trình hoàn chỉnh sẽ tốt đẹp, không chỉ là chức năng.
swish

1

Python, ký tự 174:

Nhanh chóng và đến điểm.

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

Thí dụ:

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

Đầu ra:

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

Tôi cho rằng tệp từ OS X chỉ có nhiều mục hơn.


Danh sách không nên bao gồm chính từ đó và cũng không bỏ qua dấu nháy đơn: với từ điển UNIX, nó cũng có golf'.
swish

Bạn có ý nghĩa gì khi bỏ qua các dấu nháy đơn? Sau khi đọc lại lời nhắc, tôi vẫn không thấy bạn đang làm gì.
xleviator

Nếu tôi chạy mã của bạn trên từ điển với golf'nó, nó sẽ được in.
vênh

Ah, tôi đã đọc sai lời nhắc, nhưng giờ nó đã được sửa.
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

0

Nổi loạn - 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 (với một số ý kiến):

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

Ví dụ sử dụng (được thử nghiệm trong Rebol 3 trên 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

Dưới đây là parsequy tắc được tạo để khớp với các từ tương tự như 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

Con trăn (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]

Khá hiệu quả, tôi nghĩ vậy. Ngoài ra, tôi thích cách chơi golf này trong Python.


Bạn không tính đến việc xóa hoặc thêm một ký tự.
swish
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.