심심해서 만든 문제: 팬그램

팬그램이 무엇인가요?

주어진 모든 문자가 포함된 문장을 팬그램이라고 부릅니다.

The quick brown fox jumps over the lazy dog.

이 문장에는 a-z까지 모든 문자가 빠짐없이 포함되어있으니 팬그램입니다.

문제

사용자로부터 입력을 받아 그 문장이 팬그램인지 아닌지 판별하는 프로그램을 작성하세요.
입력받은 문자열에 한국어 자음 14개가 모두 포함되어 있을경우 팬그램으로 간주합니다.

입력

  • 입력받는 횟수는 0이 아닌 다른 자연수, 한마디로 자유입니다.
  • 단, 모든 입력은 한국어로 이루어진 문자열이 주어집니다.
  • 이외에 다른 조건은 없습니다.

출력

  • 첫 줄에 팬그램이면 true 혹은 1, 아니면 false 혹은 0을 출력하시면 됩니다.

선택사항

  • 자음과 모음, 띄어쓰기가 공존하는 한국어 문자열을 입력받고 팬그램인지 아닌지 구분해보세요.

예시1

입력:

ㅎㅇ

출력:

false

예시2

입력:

ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ

출력:

true

예시3

입력:

다람쥐 헌 쳇바퀴에 타고파

출력:

1


심심해서 심심할때 풀어보시라구 심심한 문제를 만들었습니다.

예시가 한컴이었나요>>? 어디서 많이 본거같은데 기억이 안나네요./…ㄷㄷ


윈도우에서 트루타입 글꼴을 설치할 때 나오는 팬그램입니다.
영문판에서는 “The quick brown fox jumps over the lazy dog.” 이 문장을 사용합니다.

한글 코드표
요고 보면서 만들면 어떻게 될거같은데 도전정신 생기네요.

만들게 되면 어떻게 만드셨는지 알려주세요!

"C++
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

#include <io.h>
#include <fcntl.h>

int isNotPangram = 19;
vector<wchar_t> v;

// 초성 추출
wchar_t getChosung(wchar_t c) {
    // 자음+모음일 경우
    c -= 0xAC00;
    return c/(28*21);
}

bool checkChosung(wchar_t c) {
    // 이미 확인한 자음일 경우 false 반환
    if(find(v.begin(),v.end(),c) != v.end()) {
        return false;
    }
    // 첫 자음일 경우 true 반환
    v.push_back(c);
    return true;
}


int main() {
    setlocale(LC_ALL,"korean");
    wchar_t s[50];
    wcin.getline(s,sizeof(wchar_t)*50);

    for(wchar_t c : s) {
        if(!c) break;
        if(checkChosung(getChosung(c))) isNotPangram--;
    }

    if(isNotPangram) cout << "It's not Pangram!" << endl;
    else cout << "It's Pangram!" << endl;


    return 0;
}


// 초성 추출법
// t.ly/kTZZ

// 완성형 유니코드
// t.ly/Y6Js
// http://kkamagui.tistory.com/234

// 유니코드 입출력
// t.ly/2yRc

// 모음 자음 분리
// t.ly/TtAM

코드가 많이 지저분하네요

대충 요약하면, 한글을 유니코드로 받아 초성을 분리해서
초성 19개(쌍자음 포함)를 모두 돌았는지 확인하는 식으로 굴러갑니다
근데 자음만 입력하면(가나다 대신 ㄱㄴㄷ) 안 굴러갑니다 힝

금방 만들 줄 알았는데 한글을 유니코드로 받는 것부터 바로 받히네요
아직 많이 모자란가 봅니다

1 Like
1 Like

하스켈인가요?

러스트입니다

충분히 잘 만드셨습니다. 수고하셨어욤

파이썬도 취급하십니까…?

영문 텍스트 팬그램 판별 (Python)

def is_pangram(s):
	import string
	return set([c.lower() for c in s if c != ' ']) == set(string.ascii_lowercase)

한글 텍스트 자음 팬그램 판별 (Python)

hangul_chosungs = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ',  'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ']
hangul_jungsungs = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ',  'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ']
hangul_jongsugs = ['', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ',  'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ']
hangul_jaum_set = {'ㄱ', 'ㄴ', 'ㄷ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅅ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'}


def decompose_hangul(hangul_char):
    if not ord('가') <= ord(hangul_char) <= ord('힣'):
        raise TypeError(f'"{hangul_char}" is not a set of Hangul')
    
    font_index = ord(hangul_char) - ord('가')
    cho = hangul_chosungs[(font_index // 28) // 21]
    jung = hangul_jungsungs[(font_index // 28) % 21]
    jong = hangul_jongsugs[font_index % 28]
    
    if jong == '':
        return cho, jung
    return cho, jung, jong
    

def decompose_hanguls(hanguls_text):
    decomposed_hanguls = []
    for hangul_char in hanguls_text:
        try:
            decomposed_hanguls += decompose_hangul(hangul_char)
        except TypeError:
            continue
    return set(decomposed_hanguls)

    
def is_hangul_jaum_pangram(hanguls):
    decompsoed_hanguls = decompose_hanguls(hanguls)
    decomposed_hangul_jaum_set = decompsoed_hanguls & hangul_jaum_set
    return hangul_jaum_set == decomposed_hangul_jaum_set

한글 자음 팬그램 잘됩니다~!

print(is_hangul_jaum_pangram('다람쥐 헌 쳇바퀴에 타고파')) # True
print(is_hangul_jaum_pangram('정 참판 양반댁 규수 큰 교자 타고 혼례 치른 날')) # True
print(is_hangul_jaum_pangram('고양이는 아주 귀엽다')) # False
2 Likes

언어 상관없습니다!
원래 영어로 하려구 했는데 그러면 워낙 흔한 문제가 될 것 같아서 한글로 바꿨습니다. 재미있는 문제가 되었으면 좋겠네요.

러스트 살짝 찍먹 해보고 있는데 이거 너무 어려운데요? 어떻게 배우신거죠??

Python 버전도 올렸지만 심심해서 만들어본 C++ 버전… ㅋㅋ

영문 텍스트 팬그램 판별 (C++)

#include <string>
#include <set>
#include <algorithm>


bool is_pangram(const std::string& s)
{
	const static std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
	const static std::set<char> alphabet_set(alphabet.cbegin(), alphabet.cend());
	std::string lowercase;

	lowercase.reserve(s.length());
	std::for_each(s.cbegin(), s.cend(), [&](const char& c) {if (isalpha(c)) lowercase += (char)tolower(c);});
	return std::set<char>(lowercase.cbegin(), lowercase.cend()) == alphabet_set;
}

실행 코드 및 결과

#include <iostream>
#include <array>

int main(int argc, char** argv)
{
	std::array<std::string, 2> texts = {"The quick brown fox jumps over the lazy dog", "The cute cat hits the dog"};

	for (std::string& s : texts)
		std::cout << "\"" << s << "\"" << " is " << (is_pangram(s) ? "pangram" : "not pangram") << std::endl;
	return 0;
}

“The quick brown fox jumps over the lazy dog” is pangram
“The cute cat hits the dog” is not pangram

한글 텍스트 자음 팬그램 판별 (C++)

#include <string>
#include <array>
#include <set>
#include <algorithm>


/*
	= 입력값
		wc: in -> 분해하려는 한글 문자
		cho: out -> 분해된 초성
		jung: out -> 분해된 중성
		jong: out -> 분해된 종성 (종성이 없을시 \0 반환)

	= 반환값
		true -> 분해 성공
		false -> 분해 실패
*/
bool decompose_hangul(const wchar_t wc, wchar_t& cho, wchar_t& jung, wchar_t& jong)
{
	const static std::array<wchar_t, 19> chosungs = { L'ㄱ', L'ㄲ', L'ㄴ', L'ㄷ', L'ㄸ', L'ㄹ', L'ㅁ', L'ㅂ', L'ㅃ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅉ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ' };
	const static std::array<wchar_t, 21> jungsungs = { L'ㅏ', L'ㅐ', L'ㅑ', L'ㅒ', L'ㅓ', L'ㅔ', L'ㅕ', L'ㅖ', L'ㅗ', L'ㅘ', L'ㅙ', L'ㅚ', L'ㅛ', L'ㅜ', L'ㅝ', L'ㅞ', L'ㅟ', L'ㅠ', L'ㅡ', L'ㅢ', L'ㅣ' };
	const static std::array<wchar_t, 28> jongsugs = { L'\0', L'ㄱ', L'ㄲ', L'ㄳ', L'ㄴ', L'ㄵ', L'ㄶ', L'ㄷ', L'ㄹ', L'ㄺ', L'ㄻ', L'ㄼ', L'ㄽ', L'ㄾ', L'ㄿ', L'ㅀ', L'ㅁ', L'ㅂ', L'ㅄ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ' };

	if (wc < L'가' || wc > L'힣')
		return false;

	int font_index = wc - L'가';
	cho = chosungs[(int)((font_index / 28) / 21)];
	jung = jungsungs[(int)((font_index / 28) % 21)];
	jong = jongsugs[(int)(font_index % 28)];

	return true;
}


bool is_hangul_jaum_pangram(const std::wstring& ws)
{
	const static std::array<wchar_t, 14> jaums = { L'ㄱ', L'ㄴ', L'ㄷ', L'ㄹ', L'ㅁ', L'ㅂ', L'ㅅ', L'ㅇ', L'ㅈ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ' };
	const static std::set<wchar_t> jaum_set(jaums.cbegin(), jaums.cend());

	// 한글 초성/중성/종성 분해
	std::set<wchar_t> ws_hangul_set;
	std::for_each(ws.cbegin(), ws.cend(), [&](const wchar_t wc) {
		wchar_t cho, jung, jong;
		if (decompose_hangul(wc, cho, jung, jong))
		{
			ws_hangul_set.insert(cho);
			ws_hangul_set.insert(jung);
			if (jong != L'\0')
				ws_hangul_set.insert(jong);
		}
	});

	std::set<wchar_t> ws_hangul_jaum_set;
	std::set_intersection(ws_hangul_set.begin(), ws_hangul_set.end(),
						  jaum_set.cbegin(), jaum_set.cend(),
						  std::inserter(ws_hangul_jaum_set, ws_hangul_jaum_set.begin()));

	return ws_hangul_jaum_set == jaum_set;
}

실행 코드 및 결과

#include <iostream>
#include <array>

int main(int argc, char** argv)
{
	std::locale::global(std::locale("kor"));
	std::array<std::wstring, 3> hangul_texts = {L"다람쥐 헌 쳇바퀴에 타고파", L"정 참판 양반댁 규수 큰 교자 타고 혼례 치른 날", L"고양이는 아주 귀엽다"};

	for (std::wstring& ws : hangul_texts)
		std::wcout << L"\"" << ws << L"\"" << L" is " << (is_hangul_jaum_pangram(ws) ? L"pangram" : L"not pangram") << std::endl;
	return 0;
}

“다람쥐 헌 쳇바퀴에 타고파” is pangram
“정 참판 양반댁 규수 큰 교자 타고 혼례 치른 날” is pangram
“고양이는 아주 귀엽다” is not pangram

1 Like
const XS: [u16; 19] = [
    1, 1, 2, 4, 4, 8, 16, 32, 32, 64, 64, 128, 256, 256, 512, 1024, 2048, 4096, 8192
];
const YS: [u16; 28] = [
    0, 1, 1, 65, 2, 258, 8194, 4, 8, 9, 24, 40, 72, 2056, 4104, 8200, 16, 32, 96, 64, 64, 128, 256, 512, 1024, 2048, 4096, 8192
];
const ZS: [u16; 30] = [
    1, 1, 65, 2, 258, 8194, 4, 4, 8, 9, 24, 40, 72, 2056, 4104, 8200, 16, 32, 32, 96, 64, 64, 128, 256, 256, 512, 1024, 2048, 4096, 8192
];

fn encode(c: char) -> Option<u16> {
    if ('가'..='힝').contains(&c) {
        let k = c as usize - 0xAC00;
        return Some(XS[k / 588] | YS[k % 28]);
    }

    ('ㄱ'..='ㅎ').contains(&c).then(|| ZS[c as usize - 0x3131])
}

fn is_pangram(s: &str) -> bool {
    s.chars().filter_map(encode).fold(0, std::ops::BitOr::bitor) == 16383
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    println!("{}", is_pangram(s.trim()));
}
1 Like

'러스트 프로그래밍 공식 가이드’라는 책 보면서 입문했습니다

1 Like

저는 TRPL 보고 있는데… 뭔가 입문서가 아닌듯한 느낌이;;