골프 문자열 형식 ()


13

포맷 방법을 반전시킵니다.

FormatString 클래스 의 메소드 (또는 같은 등가 sprintf)는 대부분의 언어에서 사용할 수 있습니다. 기본적으로 "서식"문자열이 필요합니다. 여기에는 추가 서식이있는 자리 표시 자와 해당 자리 표시 자 대신 0 개 이상의 값이 삽입 될 수 있습니다.

당신의 임무는 선택한 언어로 역함수를 구현하는 것입니다.

API

메소드 이름은 format1또는 이어야합니다 deformat.

입력 : 첫 번째 매개 변수는 원래 형식 방법에서와 같이 "형식"문자열입니다. 두 번째 매개 변수는 구문 분석 된 문자열입니다 (아래 예 참조). 다른 매개 변수는 필요하지 않습니다.

출력 : 형식의 자리 표시 자와 함께 추출 된 값의 배열 (또는 선택 언어와 동등한 값)입니다.

자리 표시입니다 {0}, {1}, {2}, 등

잘못된 형식의 경우 오류가 발생하거나 원하는 것을 반환 할 수 있습니다.

잘못된 입력의 경우 오류가 발생하거나 원하는 것을 반환 할 수 있습니다. 동일한 형식 문자열을 사용하여 String.Format에서 생성 할 수없는 입력이 올바르지 않습니다 (예 :) '{0}{0}', 'AAB'.

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

모호

모호한 경우 적절한 답변을 반환 할 수 있습니다. 예를 들면 다음과 같습니다.

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

더 많은 규칙

  • 더 쉽게 만들기 위해 실제로 서식을 지원할 필요가 없습니다. 선행 0, 소수점 또는 반올림 문제에 대한 모든 것을 잊을 수 있습니다. 값을 문자열로 생성하십시오.
  • 사소하지 않게하기 위해 정규 표현식은 허용되지 않습니다 .
  • 입력에서 중괄호를 처리 할 필요가 없습니다 (즉, 두 번째 입력 매개 변수에 {s 또는 }s가 포함되지 않음 ).

승리

이것은 ! ( "이것은 스파르타입니다!"로 읽어야합니다.) 가장 짧은 길이의 올바른 기능이 승리합니다. 표준 허점 은 금지되어 있습니다.


이 예 deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB']에서 대신 우리에게 주어진다면 deformat('{0}{1}{0}', 'AAAA')?
xnor

@xnor - 우리는 모호성을 가지고 있고, 다음의 각 유효한 출력 것보다 : ['', 'AAAA'], ['A', 'AA'],['AA', '']
야곱

그런 다음 출력 할 수 deformat('{0}{1}{0}', 'ABBA') => ['', 'ABBA']있습니까? 그렇다면 모든 문자열이 두 번 이상 나타나지 않으면 저렴한 솔루션이 있습니다.
xnor

저렴한 솔루션도 효과가 deformat('{0}_{1}_{0}', 'A_BB_A')있습니까?
Jacob

아, 나는 결과에서 실제 인물에 대해 잊어 버렸습니다. 나는 아직도 알고리즘 적으로 얼마나 어려운지 내 머리를 감싸려고 노력하고 있습니다. 내가 정말 나쁜 사례를 만들 수 있는지 살펴 보겠습니다.
xnor

답변:


2

하스켈, 220 자

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

동일한 패턴 ( {1}vs {01})에 여러 표현을 사용하는 경우 중단됩니다. 동일한 표현을 적용하지 않고 대신 하나의 표현에 대한 일치를 모두 버립니다.

mapKeys((0+).read)$10 개 이상의 패턴 일치가 중요하지 않거나 동일한 길이의 패딩이 필요하거나 패턴의 문자열 순서가 허용 가능한 경우 생략하여 19자를 저장할 수 있습니다. 어쨌든 패턴이 첫 번째 인수에서 생략되면 결과에서도 생략됩니다.

!!0끝에서 제거 format1하면 첫 번째 솔루션이 아닌 모든 솔루션 목록 이 반환됩니다.

골프 전 :

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

whi가 있습니까 (0+)? 글을 짧게 읽는 것이 아닙니까?
자랑스런 Haskeller

@proudhaskeller read는 모호한 유형으로 당신을 떠납니다. Haskell은 어떤 키를 읽을 수있는 정렬 가능한 유형인지 모릅니다. +0Haskell이 이미 임의의 선택을 할 수 있고 정수로가는 숫자를 강제합니다.
John Dvorak

2

루비, 312 자

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

길이가 0 인 일치를 선호 하여 질문의 선호 솔루션 대신 ABBA솔루션을 만들어 5자를 절약 할 수 있습니다 ['', 'ABBA']. 예제를 사양의 내재 된 부분으로 해석하기로 선택했습니다.


1

파이썬, 208 자, 불완전하지만.

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

이 함수는 입력 문자열에서 여는 중괄호를 찾을 때까지 두 문자열을 동시에 스윕하여 자리 표시자를 나타냅니다.

그런 다음 자리 표시자가 이미 확장되었다고 가정하고 지금까지 찾은 값 목록을 확인하여 출력 문자열의 색인을 통과시킵니다.

확장되지 않은 경우 값 목록에 새 항목을 추가하고 입력 문자열에서 자리 표시 자 뒤의 문자에 도달 할 때까지 출력 문자열에서 문자를 추가하기 시작합니다.

입력 문자열의 끝에 도달하면 지금까지 찾은 값을 반환합니다.


간단한 입력에는 효과적이지만 여러 가지 문제가 있습니다.

  • 입력의 각 자리 표시 자 뒤에 알려진 구분 기호가 필요하므로 "{0} {1}"바로 옆에 자리 표시 자와 함께 작동하지 않습니다. 이것이 두 문자열에 공백 문자를 추가 해야하는 이유입니다.

  • 각 자리 표시 자의 첫 번째 인스턴스가 "{ 0 } { 1 } {1} {0} { 2 }" 순서로되어 있다고 가정합니다 .

  • 처음 10 자리 표시자는 3 자 길이라고 가정하기 때문에 작동합니다.

  • 모호한 경우를 전혀 처리하지 않습니다.


1

C ++ 11 코드, 386 자

#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;}

format1 함수는 입력으로 2 개의 문자열을 가지며 (const char *) 키 정수 (패턴)가있는 해시 맵을 리턴하며 value는 식별 된 문자열입니다. 아무것도 발견되지 않거나 오류가 발생하면 빈 해시 맵이 반환됩니다.

용법:

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

산출:

1=one
2=two

예 2 :

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

산출:

one and two

패턴은 십진수로 표시 MAXINT되며 오버플로 보다 큰 입력 이지만 여전히 작동합니다.

다른 프로그래밍 언어에는 더 작은 솔루션이 있지만 이것이 가장 작은 C ++입니다. :)

이것은 골프 전의 코드입니다.

#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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.