내성 프로그래밍 : 소스와 출력을 분석하는 코드


13

총 문자 개수와 각 문자 소스의 주파수를 출력하는 프로그램을 작성 하고 , 출력한다. 예제에 설명 된 형식을 따라야합니다.

코드가

abb1

출력은

My source has 4 characters.
1 is "a"
2 are "b"
1 is "1"
Besides unquoted numbers, my output has 383 characters.
34 are "
"
79 are " "
63 are """
2 are "'"
2 are ","
4 are "."
2 are "1"
2 are "B"
2 are "I"
2 are "M"
39 are "a"
4 are "b"
6 are "c"
4 are "d"
38 are "e"
3 are "g"
5 are "h"
4 are "i"
4 are "m"
3 are "n"
8 are "o"
3 are "p"
2 are "q"
38 are "r"
12 are "s"
8 are "t"
7 are "u"
3 are "y"
It's good to be a program.

(출력은 stdout으로 이동해야합니다.)

예를 들어, 결과에는 두 개의 대문자 m이 포함되어 있습니다. 에 대한 My하나 2 are "M". 출력이 어떤 식 으로든 모순되지 않도록 모든 문자에 대해 true를 유지해야합니다.

따옴표없는 숫자는 만족할 수없는 주파수 세트를 피하기 위해 출력에서 ​​무시됩니다. 예를 들어, 1 is "1"두 1을 모두 세면 올바르지 않습니다. 읽어야 2 are "1"하지만 다시 하나만 있습니다.

형식 설명

  • 단일 문자 발생에는 "is"를 사용해야합니다.

  • "are"는 여러 문자 발생에 사용해야합니다.

  • "is"는 불필요하기 때문에 출력 문자 목록에 나타나지 않아야합니다. 1 is 'Z'Z 자체를 참조하므로 전체 라인을 제거 할 수 있습니다.

  • 세 개의 전체 문장 구가 문자 빈도 목록 사이에 순서대로 나타나야합니다 (예 참조). 따라서 출력은로 시작 My source...하고로 끝납니다 ...be a program.. 출력 끝에 줄 바꿈이 없습니다.

  • 문자 빈도 목록 자체는 임의의 순서로있을 수 있습니다.

  • 줄 바꿈은 하나의 문자로 계산됩니다 (\ r \ n 인 경우).

포맷 검사기

다음 Python 스크립트는 코드와 출력을 문자열로 가져오고 출력에 모순이 없음을 주장합니다. 문제가있는 경우 유용한 오류 메시지를 제공합니다. http://ideone.com/6H0ldu 에서 온라인으로 실행할 수 있습니다 . 그것은 오탐 (false positive) 또는 부정 (negative)을 제공하지 않습니다 (오류가 없다고 가정).

#Change the CODE and OUTPUT strings to test your program

CODE = r'''abb1'''

OUTPUT = r'''My source has 4 characters.
1 is "a"
2 are "b"
1 is "1"
Besides unquoted numbers, my output has 383 characters.
34 are "
"
79 are " "
63 are """
2 are "'"
2 are ","
4 are "."
2 are "1"
2 are "B"
2 are "I"
2 are "M"
39 are "a"
4 are "b"
6 are "c"
4 are "d"
38 are "e"
3 are "g"
5 are "h"
4 are "i"
4 are "m"
3 are "n"
8 are "o"
3 are "p"
2 are "q"
38 are "r"
12 are "s"
8 are "t"
7 are "u"
3 are "y"
It's good to be a program.'''

#######################################################

import re

amountPattern = r'(\d+) (is|are) "(.)"\n'

class IntrospectionException(Exception):
    pass

def getClaimedAmounts(string, errorOnIs):
    groups = re.findall(amountPattern, string, re.DOTALL)

    for amount, verb, char in groups:
        if verb == 'is':
            if errorOnIs:
                raise IntrospectionException('\'1 is "%s"\' is unnecessary' % char)
            elif amount != '1':
                raise IntrospectionException('At "%s", %s must use "are"' % (char, amount))
        elif verb == 'are' and amount == '1':
            raise IntrospectionException('At "%s", 1 must use "is"' % char)

    amounts = {}
    for amount, verb, char in groups:
        if char in amounts:
            raise IntrospectionException('Duplicate "%s" found' % char)
        amounts[char] = int(amount)
    return amounts

def getActualAmounts(string):
    amounts = {}
    for char in string:
        if char in amounts:
            amounts[char] += 1
        else:
            amounts[char] = 1
    return amounts

def compareAmounts(claimed, actual):
    for char in actual:
        if char not in claimed:
            raise IntrospectionException('The amounts list is missing "%s"' % char)
    for char in actual: #loop separately so missing character errors are all found first
        if claimed[char] != actual[char]:
            raise IntrospectionException('The amount of "%s" characters is %d, not %d' % (char, actual[char], claimed[char]))
    if claimed != actual:
        raise IntrospectionException('The amounts are somehow incorrect')

def isCorrect(code, output):
    p1 = r'^My source has (\d+) characters\.\n'
    p2 = r'Besides unquoted numbers, my output has (\d+) characters\.\n'
    p3 = r"It's good to be a program\.$"
    p4 = '%s(%s)*%s(%s)*%s' % (p1, amountPattern, p2, amountPattern, p3)

    for p in [p1, p2, p3, p4]:
        if re.search(p, output, re.DOTALL) == None:
            raise IntrospectionException('Did not match the regex "%s"' % p)

    claimedCodeSize = int(re.search(p1, output).groups()[0])
    actualCodeSize = len(code)
    if claimedCodeSize != actualCodeSize:
        raise IntrospectionException('The code length is %d, not %d' % (actualCodeSize, claimedCodeSize))

    filteredOutput = re.sub(r'([^"])\d+([^"])', r'\1\2', output)

    claimedOutputSize = int(re.search(p2, output).groups()[0])
    actualOutputSize = len(filteredOutput)
    if claimedOutputSize != actualOutputSize:
        raise IntrospectionException('The output length (excluding unquoted numbers) is %d, not %d' % (actualOutputSize, claimedOutputSize))

    splitIndex = re.search(p2, output).start()

    claimedCodeAmounts = getClaimedAmounts(output[:splitIndex], False)
    actualCodeAmounts = getActualAmounts(code)
    compareAmounts(claimedCodeAmounts, actualCodeAmounts)

    claimedOutputAmounts = getClaimedAmounts(output[splitIndex:], True)
    actualOutputAmounts = getActualAmounts(filteredOutput)
    compareAmounts(claimedOutputAmounts, actualOutputAmounts)

def checkCorrectness():
    try:
        isCorrect(CODE, OUTPUT)
        print 'Everything is correct!'
    except IntrospectionException as e:
        print 'Failed: %s.' % e

checkCorrectness()

채점

이것은 코드 골프입니다. 가장 적은 문자로 제출하면 이깁니다. 제출물이 유효하려면 형식 검사기를 통과해야합니다. 표준 허점이 적용 되지만 자체 소스 코드를 읽거나 출력을 하드 코딩 할 수 있습니다 .


자신의 소스 파일을 읽을 수 있습니까?
Ventero

@MrLore 다른 오류가있을 수 있지만 트리플 따옴표 ( '``)가 여전히 백 슬래시로 탈출한다는 것을 깨달았습니다. 이것은 문제와 관련이있을 수 있습니다. 지금 고치고 있습니다.
Calvin 's Hobbies

@Ventero 확실히!
Calvin 's Hobbies

@MrLore 정규 표현식은 잘못된 긍정을 허용합니다. 삼중 따옴표 안에 백 슬래시 문제를 해결하려면 원시 문자열 ( r'''CODE''')을 사용하십시오.
Ventero

1
@MrLore 이스케이프되지 않은 점을 수정했습니다. 알아 주셔서 감사합니다!
Calvin 's Hobbies

답변:


2

CJam-189

{`"_~"+:T;"Besides unquoted numbers, my output has &It's good to be a program.&My source has & characters.
"'&/~_]:X2=T,X3=3i({T_&:B{TI/,(" are ":AM`I*N}fIXK=]o
XBA`N+f+2*+s:T,X3=}fK'q];}_~

http://cjam.aditsu.net/ 에서 시도 하십시오

산출:

My source has 189 characters.
3 are "{"
3 are "`"
6 are """
4 are "_"
3 are "~"
4 are "+"
5 are ":"
5 are "T"
2 are ";"
3 are "B"
8 are "e"
9 are "s"
2 are "i"
3 are "d"
17 are " "
6 are "u"
2 are "n"
2 are "q"
8 are "o"
6 are "t"
3 are "m"
2 are "b"
7 are "r"
4 are ","
2 are "y"
2 are "p"
3 are "h"
7 are "a"
5 are "&"
4 are "I"
3 are "'"
2 are "g"
2 are "."
2 are "M"
3 are "c"
2 are "
"
2 are "/"
3 are "]"
5 are "X"
2 are "2"
4 are "="
3 are "3"
2 are "("
2 are "A"
2 are "*"
2 are "N"
3 are "}"
3 are "f"
2 are "K"
Besides unquoted numbers, my output has 988 characters.
3 are "B"
108 are "e"
11 are "s"
3 are "i"
5 are "d"
214 are " "
8 are "u"
4 are "n"
3 are "q"
9 are "o"
9 are "t"
5 are "m"
4 are "b"
108 are "r"
3 are ","
4 are "y"
4 are "p"
6 are "h"
108 are "a"
3 are "I"
3 are "'"
4 are "g"
5 are "."
3 are "M"
7 are "c"
102 are "
"
2 are "{"
198 are """
2 are "`"
2 are "_"
2 are "~"
2 are "+"
2 are ":"
2 are "T"
2 are ";"
2 are "&"
2 are "/"
2 are "]"
2 are "X"
2 are "2"
2 are "="
2 are "3"
2 are "("
2 are "A"
2 are "*"
2 are "N"
2 are "}"
2 are "f"
2 are "K"
It's good to be a program.

11

루비, 269 (311, 367) 자

이 도전에 대한 세 가지 솔루션이 있습니다. 그들 각각은 다른 트릭을 사용합니다 :

"적절한"솔루션, 367 자 :

가장 긴 솔루션은 개념 증명 일 뿐이며, 트릭없이이 과제를 해결할 수 있으며 거의 ​​완전히 골프가 아닙니다. 그것은 진정한 quine (즉, 파일에서 읽지 않고 자체 소스 코드를 생성 함)이며 실제로 인쇄하는 모든 숫자 (코드 길이, 출력 길이, 문자 발생)를 계산합니다. quine이 작동하는 방식으로 인해 모든 코드는 한 줄에 있어야하며 문자열 리터럴 안에 있어야합니다.

eval r="S='eval r=%p'%r;O=-~$.;q=\"My source has \#{S.size}\"+(X=' characters.\n')+S.chars.uniq.map{|c|[k=S.count(c),k>O ? :are: :is,?\"+c+?\"]*' '}*$/+'\nBesides unquoted numbers, my output has ';r=(w=q+X+s=\"It's good to be a program.\").scan(D=/\\D/).uniq;$><<q<<(w+v=r.map{|c|j=' are \"\n\"';(-~(w+j*r.size).count(c)).to_s+(j[~O]=c;j)}*$/+$/).scan(D).size<<X+v+s"

부분적으로 하드 코딩 된 출력, 311 자 :

다음으로 가장 짧은 솔루션은 두 가지 트릭을 사용하지만 여전히 진실입니다.-소스 코드에서 문자가 정확히 한 번만 나타나지 않습니다. 그렇게하면 출력물을 인쇄해야하는지 is또는 are출력의 전반부에 넣을지를 결정할 필요가 없습니다 . 또한 전체 출력 크기를 계산하는 것이 조금 더 쉽습니다 (실제로 그렇게 할 필요는 없지만). -전체 출력 크기가 하드 코딩됩니다. 소스 코드의 고유 한 문자 수 (일반적으로 이러한 문자 중 한 번만 발생하는 문자 수)에만 의존하기 때문에 미리 계산하기가 쉽습니다.

코드 앞에는 두 개의 매우 중요한 줄 바꿈이 있으며, StackExchange는 코드 블록에 표시되지 않습니다. 따라서 코드의 일부 가 아닌 줄 바꿈을 추가하면 앞에 줄을 추가했습니다 .

#


eval R="I=$/+$/+'eval R=%p'%R;?\\4>w='%d are \"%s\"';B=\"My source has \#{I.size}\#{X=\" characters.\n\"}\#{z=(m=I.chars.uniq).map{|x|w%[I.count(x),x]}*$/}\nBesides unquoted numbers, my output has 1114\"+X;$><<B+m.map{|c|w%[(B+z+$M=\"\nIt's good to be a program.\").gsub!(/\\d++(?!\")/,'').count(c),c]}*$/+$M"

최단 솔루션, 269 자 :

가장 짧은 솔루션은 추가로 자체 소스 길이를 하드 코딩합니다. 아직 소스 코드의 일부가 아닌 변수 이름을 사용하면 소스 코드의 모든 문자 (하드 코드 된 길이의 자릿수 포함)가 적어도 두 번 발생하는 "고정 점"을 찾을 수 있습니다.

이 솔루션은 또한 생성하는 대신 코드 파일에서 자체 소스 코드를 읽기만하면 더 많은 문자를 절약 할 수 있습니다. 좋은 부작용으로, 이것은 코드를 훨씬 더 "읽을 수있게"합니다 (그러나 에서 읽을 수있는 코드에 관심이있는 사람 ...). 이제 코드는 더 이상 문자열 리터럴 안에있을 필요가 없습니다.

U='%d are "%s"'
O=IO.read$0
?\126>B="My source has 269#{X=" characters.
"}#{z=(m=O.chars.uniq).map{|c|U%[O.count(c),c]}*$/}
Besides unquoted numbers, my output has 1096"+X
$><<B+m.map{|c|U%[(B+z+$M="
It's good to be a program.").gsub!(/\d++(?!")/,"").count(c),c]}*$/+$M

또한 코드를 확인하는 데 필요한 복사 붙여 넣기를 줄이기 위해 테스트 스크립트를 약간 수정했습니다. 의 정의로 대체함으로써 CODEOUTPUT하여

import subprocess

CODE = open("packed.rb").read()
OUTPUT = subprocess.check_output(["ruby", "packed.rb"])

print CODE
print len(CODE)

이제 스크립트가 자동으로 코드를 실행하고 출력을 읽은 다음 코드 파일에서 소스 코드를 가져옵니다.


가장 짧은 코드로 생성 된 출력은 다음과 같습니다.

My source has 269 characters.
3 are "U"
7 are "="
3 are "'"
4 are "%"
6 are "d"
17 are " "
11 are "a"
9 are "r"
9 are "e"
11 are """
11 are "s"
6 are "
"
4 are "O"
2 are "I"
10 are "."
6 are "$"
2 are "0"
2 are "?"
2 are "\"
2 are "1"
2 are "2"
3 are "6"
2 are ">"
4 are "B"
3 are "M"
2 are "y"
9 are "o"
10 are "u"
12 are "c"
4 are "h"
2 are "9"
2 are "#"
4 are "{"
2 are "X"
8 are "t"
4 are "}"
2 are "z"
6 are "("
7 are "m"
5 are "n"
2 are "i"
2 are "q"
6 are ")"
4 are "p"
4 are "|"
2 are "["
4 are ","
2 are "]"
2 are "*"
4 are "/"
3 are "b"
7 are "+"
2 are "<"
3 are "g"
2 are "!"
Besides unquoted numbers, my output has 1096 characters.
2 are "U"
2 are "="
3 are "'"
2 are "%"
5 are "d"
238 are " "
120 are "a"
120 are "r"
120 are "e"
222 are """
11 are "s"
114 are "
"
2 are "O"
3 are "I"
5 are "."
2 are "$"
2 are "0"
2 are "?"
2 are "\"
2 are "1"
2 are "2"
2 are "6"
2 are ">"
3 are "B"
3 are "M"
4 are "y"
9 are "o"
8 are "u"
7 are "c"
6 are "h"
2 are "9"
2 are "#"
2 are "{"
2 are "X"
9 are "t"
2 are "}"
2 are "z"
2 are "("
5 are "m"
4 are "n"
3 are "i"
3 are "q"
2 are ")"
4 are "p"
2 are "|"
2 are "["
3 are ","
2 are "]"
2 are "*"
2 are "/"
4 are "b"
2 are "+"
2 are "<"
4 are "g"
2 are "!"
It's good to be a program.

쉽게 테스트 할 수 있도록 코드와 출력의 최종 사본을 게시 할 수 있습니까? 코드 자체는 출력되지 않아야하며 출력은 개행 문자가 아닌 기간으로 끝나야합니다.
Calvin 's Hobbies

@ Calvin'sHobbies 첫 번째 코드 블록은 실제 코드입니다. 그래도 최종 줄 바꿈으로 출력을 인쇄하므로 문제를 해결하는 데 몇 분이 걸립니다 (이것은 사양에서 분명히 언급 해야하는 것입니다).
Ventero

물론, 방금 사양을 업데이트했습니다.
Calvin 's Hobbies

@ Calvin'sHobbies Done입니다. 첫 번째 코드 블록은 두 번째 코드 블록에 의해 생성되는 실제 코드 입니다 (그래서 코드를 작성하는 동안 문자열 이스케이프 및 모든 것을 처리 할 필요가 없습니다).
Ventero
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.