Định dạng nghịch đảo của Golf String ()


13

Đảo ngược phương thức Format.

Các Formatphương thức của lớp String (hoặc equivallent, chẳng hạn như sprintf) có sẵn trong hầu hết các ngôn ngữ. Về cơ bản, nó có một chuỗi "Định dạng" có thể chứa các trình giữ chỗ với một số định dạng bổ sung và không có hoặc nhiều giá trị được chèn thay vì các trình giữ chỗ đó.

Nhiệm vụ của bạn là thực hiện chức năng nghịch đảo trong ngôn ngữ bạn chọn.

API

Tên phương thức nên là format1hoặc deformat.

Đầu vào : Tham số thứ nhất sẽ là chuỗi "Định dạng", giống như trong phương thức định dạng ban đầu. Tham số thứ 2 sẽ là chuỗi được phân tích cú pháp (xem ví dụ bên dưới). Không có thông số khác là cần thiết cũng không được phép.

Đầu ra : một mảng (hoặc tương đương với ngôn ngữ của sự lựa chọn của bạn) các giá trị được trích xuất tương ứng với các phần giữ chỗ trong định dạng.

Giữ chỗ là {0}, {1}, {2}vv

Trong trường hợp định dạng xấu, bạn có thể đưa ra lỗi hoặc trả lại bất cứ thứ gì bạn thích.

Trong trường hợp đầu vào không hợp lệ, bạn có thể đưa ra lỗi hoặc trả lại bất cứ thứ gì bạn thích. Đầu vào không hợp lệ sao cho String.Format không thể tạo bằng chuỗi định dạng tương tự, ví dụ : '{0}{0}', 'AAB'.

Ví dụ

deformat('{0} {1}', 'hello world') => ['hello', 'world']
deformat('http{0}://', 'https://') => ['s']
deformat('http{0}://', 'http://') => [''] // array of one item which is an empty string
deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB']

Sự mơ hồ

Trong trường hợp mơ hồ, bạn có thể trả lại bất kỳ câu trả lời phù hợp. Ví dụ:

deformat('{0} {1}', 'Edsger W. Dijkstra')
// both ['Edsger', 'W. Dijkstra'] and ['Edsger W.', 'Dijkstra'] are applicable.

Một số quy tắc khác

  • Để làm cho nó dễ dàng hơn, thực sự không cần phải hỗ trợ định dạng. Bạn có thể quên tất cả về các vấn đề số 0, dấu thập phân hoặc làm tròn hàng đầu. Chỉ cần tạo các giá trị dưới dạng chuỗi.
  • Để làm cho nó không tầm thường, Biểu thức chính quy không được phép .
  • Bạn không cần phải chăm sóc các dấu ngoặc nhọn trong đầu vào (tức là tham số đầu vào thứ 2 sẽ không chứa bất kỳ {s hoặc }s nào).

Chiến thắng

Đây là ! (nên được đọc là "Đây là Sparta!") chức năng chính xác có độ dài chiến thắng ngắn nhất. Sơ hở tiêu chuẩn bị cấm.


Trong ví dụ deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB'], nếu chúng ta được đưa ra deformat('{0}{1}{0}', 'AAAA')thì sao?
xnor

@xnor - hơn chúng ta có một sự mơ hồ, và mỗi người trong số những điều sau đây sẽ là một kết quả hợp lệ: ['', 'AAAA'],['A', 'AA'] ,['AA', '']
Jacob

Ai đó có thể đã xuất ra deformat('{0}{1}{0}', 'ABBA') => ['', 'ABBA'] ? Nếu vậy, có một giải pháp rẻ tiền trừ khi mỗi chuỗi xuất hiện ít nhất hai lần.
xnor

giải pháp giá rẻ của bạn cũng sẽ làm việc cho deformat('{0}_{1}_{0}', 'A_BB_A')?
Jacob

Ồ, tôi hiểu rồi, tôi đã quên mất các nhân vật thực tế trong kết quả. Tôi vẫn đang cố gắng che giấu sự khó khăn của thuật toán này. Hãy để tôi xem nếu tôi có thể tạo nên một ví dụ thực sự đồi trụy.
xnor

Câu trả lời:


2

Haskell, 220 ký tự

import Data.Map;f""""=[empty]
f('{':b)d=[insert k m b|(k,('}':a))<-lex b,(m,c)<-[splitAt n d|n<-[0..length d]],b<-f a c,notMember k b||b!k==m]
f(x:b)(y:d)|x==y=f b d;f _ _=[];format1 x y=elems$mapKeys((0+).read)$f x y!!0

Phá vỡ nếu bạn sử dụng nhiều biểu diễn cho cùng một mẫu ( {1}vs {01}) - không thực thi quyền bình đẳng của chúng, loại bỏ các kết quả khớp cho tất cả trừ một đại diện thay thế.

Có thể lưu 19 ký tự bằng cách bỏ qua mapKeys((0+).read)$nếu thứ tự phù hợp của các mẫu trên 10 mẫu không thành vấn đề hoặc nếu có thể yêu cầu đệm theo cùng độ dài hoặc nếu việc sắp xếp chuỗi các mẫu có thể chấp nhận được. Trong mọi trường hợp, nếu một mẫu bị bỏ qua từ đối số đầu tiên, thì nó cũng bị bỏ qua khỏi kết quả.

Loại bỏ !!0từ cuối làm cho format1trả về danh sách tất cả các giải pháp, thay vì chỉ là giải pháp đầu tiên.

trước khi chơi golf:

import Data.Map
import Control.Monad

cuts :: [a] -> [([a],[a])]
cuts a=[splitAt n a | n <- [0..length a]]

f :: String -> String -> [Map String String]
-- empty format + empty parsed = one interpretation with no binding
f "" "" = [empty]
-- template-start format + some matched = branch search
f ('{':xs) ys = do
    let [(key, '}':xr)] = lex xs
    (match, yr) <- cuts ys
    b <- f xr yr
    guard $ notMember key b || b!key == match
    return $ insert key match b
-- non-empty format + matching parsed = exact match
f (x:xs) (y:ys) | x == y = f xs ys
-- anything else = no interpretation
f _ _ = []

deformat :: String -> String -> [String]
deformat x y = elems $ mapKeys ((0+).read) $ head $ f x y

Có ai ở đó không (0+)? không chỉ viết ngắn hơn sao?
tự hào

@proudhaskeller chỉ là một loại readbạn mơ hồ. Haskell không biết loại nào có thể đọc được các phím. +0buộc một số, từ đó Haskell đã có thể đưa ra lựa chọn tùy ý và đi tìm số nguyên.
John Dvorak

2

Ruby, 312 ký tự

class String
def-@
self[0,1].tap{self[0,1]=''}end
end
def format1 f,s,r=[]
loop{if'{'==c=-f
n,f=f.split('}',2)
[*1..s.length,0].each{|i|next if'{'!=f[0]&&s[i]!=f[0]
if u=format1((g=f.gsub("{#{n}}",q=s[0,i])).dup,s[i..-1],r.dup)
r,s,f=u,s[i..-1],g
r[n.to_i]=q
break
end}else
c!=-s&&return
end
""==c&&break}
r
end

5 ký tự có thể được lưu bằng cách ưu tiên các kết quả trùng khớp có độ dài bằng 0, tạo ra ABBAgiải pháp ['', 'ABBA'], thay vì giải pháp ưa thích của câu hỏi. Tôi đã chọn giải thích các ví dụ như là một phần ngụ ý của đặc tả.


1

Python, 208 ký tự, mặc dù không đầy đủ.

def format1(i,o):
 i+=" ";o+=" ";x=y=0;s=[]
 while x<len(i):
  if i[x]=="{":
   try:y+=len(s[int(i[x+1])])
   except:
    s+=[""]
    while o[y]!=i[x+3]:s[int(i[x+1])]+=o[y];y+=1
   x+=3
  x+=1;y+=1
 return s

Hàm quét đồng thời cả hai chuỗi, cho đến khi tìm thấy dấu ngoặc mở trong chuỗi đầu vào, biểu thị một trình giữ chỗ.

Sau đó, nó giả sử trình giữ chỗ đã được mở rộng và cố gắng nâng chỉ mục của chuỗi đầu ra qua nó bằng cách xem trong danh sách các giá trị được tìm thấy cho đến nay.

Nếu nó chưa được mở rộng, nó sẽ thêm một mục mới vào danh sách các giá trị và bắt đầu thêm các ký tự từ chuỗi đầu ra cho đến khi nó đến ký tự sau trình giữ chỗ trong chuỗi đầu vào.

Khi đến cuối chuỗi đầu vào, nó sẽ trả về các giá trị được tìm thấy cho đến nay.


Nó hoạt động tốt cho các đầu vào đơn giản, nhưng nó có một số vấn đề:

  • Nó yêu cầu một dấu phân cách đã biết sau mỗi trình giữ chỗ trong đầu vào, vì vậy nó không hoạt động với các trình giữ chỗ ngay cạnh nhau tức là "{0} {1}". Đây là lý do tại sao tôi cần nối một char không gian cho cả hai chuỗi.

  • Nó giả sử các trường hợp đầu tiên của mỗi trình giữ chỗ theo thứ tự, ví dụ: "{ 0 } { 1 } {1} {0} { 2 }".

  • Nó chỉ hoạt động cho 10 chỗ dành sẵn đầu tiên vì nó giả sử rằng chúng dài cả 3 ký tự.

  • Nó hoàn toàn không xử lý các trường hợp mơ hồ :(


1

Mã C ++ 11, 386 ký tự

#include <string>
#include <map>
using namespace std;using _=map<int,string>;using X=const char;_ format1(X*p,X*s,_ k=_()){_ r;while(*p!='{'){if(!*p||!*s){return*p==*s?k:r;}if(*p++!=*s++)return r;}int v=0;while(*++p!='}'){v=v*10+(*p-48);}p++;if(k.find(v)!=k.end()){return format1((k[v]+p).c_str(),s,k);}while((r=format1(p,s,k)).empty()){k[v]+=*s++;if(!*s){return*p==*s?k:r;}}return r;}

Hàm format1 có 2 chuỗi là đầu vào (const char *) và trả về một hàm băm với số nguyên khóa (mẫu) và giá trị là chuỗi được xác định. Nếu không có gì được tìm thấy hoặc có bất kỳ lỗi nào, một hashmap trống được trả về.

Sử dụng:

for (auto v : format1("{1} {2}", "one two")){
    cout << v.first << "=" << v.second << endl;
}

Đầu ra:

1=one
2=two

Ví dụ 2:

auto v = format1("{1} {2}", "one two");
cout << v[1] << " and " << v[2] << endl;

Đầu ra:

one and two

Các mẫu được biểu diễn thập phân, đầu vào lớn hơn MAXINTsẽ tràn nhưng nó vẫn hoạt động.

Mặc dù có các giải pháp nhỏ hơn trong các ngôn ngữ lập trình khác, đây là C ++ nhỏ nhất - chưa! :)

Đây là mã trước khi chơi golf:

#include <string>
#include <map>
using namespace std;

using res = map<int,string>;

res format1(const char* p, const char* s, res k=res()){
    res r; // intermediate result, empty until the end
    // match until first '{'
    while (*p != '{'){
        if (!*p || !*s){
            // exit case
            return ((*p == *s) ? k : r); // == 0
        }
        if (*p++ != *s++)
               return r;
    }

    // *p == '{'
    int v = 0;
    while(*++p != '}'){
        v = v*10 + (*p - '0');
    }
    p++; // advance past '}'

    // match back-references
    if (k.find(v) != k.end()){
       return format1((k[v]+p).c_str(), s, k);
    }

    // recursive search
    while ( (r=format1(p, s, k)).empty() ){
        k[v] += *s++;
        if (!*s){
            return *p == *s ? k : r;
        }
    }
    return r;
}
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.