Python Programming
  • Home
  • Intro
    • History & Background
    • Python Setup
  • QPB
    • Part I: Chapter 1-3
    • Part II
    • 5. Lists, Tuples, Sets
  • Exercises
    • Chapter 5: Lists, Tuples, Sets
    • Chapter 6: Strings
    • Chapter 7: Dictionaries
    • Chapter 8: Control flow
    • Chapter 9: Functions
    • Chapter 14: Exceptions
    • Chapter 15: Classes
  • Exploring Data
    • NumPy & pandas
    • Visualization
  • Library System
  • Netflix Movie Analysis
    • Notes
    • Project-Native
    • Project-pandas
  • References
    • QPB Part 1
    • QPB Part 2
    • QPB Part 3
    • QPB Part 4

On this page

  • 문제 1: 문자 변환 테이블 (translate와 maketrans)
  • 문제 2: 문자열 정렬과 패딩
  • 문제 3: 대소문자 변환 활용
  • 문제 4: format() 메서드 활용
  • 문제 5: 파일 이름 처리
  • 문제 6: 텍스트 줄 정렬 및 래핑
  • 문제 7: 문자열 비교와 정렬
  • 문제 8: 패스워드 유효성 검증
  • 문제 9: 로그 파일 파싱
  • 문제 10: CSV 데이터 처리
  • 문제 11**: 텍스트 감정 분석기
  • 문제 12**: 간단한 마크다운 파서

Exercises: Chapter 6 - Set 2

Chapter 6: Strings - 연습문제 Set 2

문제 1: 문자 변환 테이블 (translate와 maketrans)

주어진 암호화된 메시지를 복호화하세요. 암호는 간단한 치환 암호(Caesar cipher 변형)입니다:

encrypted = "Kbsklw sc qj jucknds oqkbkfqs."

치환 규칙: - ‘a’ → ‘e’, ‘e’ → ‘a’, ‘i’ → ‘o’, ‘o’ → ‘i’, ‘u’ → ‘y’ - 대문자도 동일하게 치환

요구사항: 1. maketrans()를 사용하여 변환 테이블 생성 2. translate()를 사용하여 복호화 3. 복호화된 메시지 출력

힌트: maketrans()의 첫 번째와 두 번째 인자에 각각 치환 전 문자와 치환 후 문자를 넣으세요.

# 여기에 코드를 작성하세요
encrypted = "Kbsklw sc qj jucknds oqkbkfqs."

문제 2: 문자열 정렬과 패딩

주어진 상품 목록을 보기 좋게 정렬하여 출력하세요:

products = [
    ("Apple", 1200),
    ("Banana", 500),
    ("Cherry", 2500),
    ("Date", 1800),
    ("Elderberry", 3200)
]

요구사항: 1. 상품명은 15자 폭, 왼쪽 정렬 2. 가격은 10자 폭, 오른쪽 정렬 3. 가격에는 천 단위 구분 쉼표 추가 4. 헤더와 구분선 추가

출력 예시:

=================================
Product Name    |     Price
=================================
Apple           |     1,200
Banana          |       500
Cherry          |     2,500
Date            |     1,800
Elderberry      |     3,200
=================================

힌트: ljust(), rjust(), center() 메서드 또는 f-string 포맷 지정자를 사용하세요.

# 여기에 코드를 작성하세요
products = [
    ("Apple", 1200),
    ("Banana", 500),
    ("Cherry", 2500),
    ("Date", 1800),
    ("Elderberry", 3200)
]

문제 3: 대소문자 변환 활용

다음 문자열들을 각각의 요구사항에 맞게 변환하세요:

strings = [
    "hello world",
    "PYTHON PROGRAMMING",
    "Data Science",
    "machine_learning_basics"
]

변환 작업: 1. 첫 번째 문자열: 각 단어의 첫 글자만 대문자 (Title Case) 2. 두 번째 문자열: 대소문자 반전 (Swap Case) 3. 세 번째 문자열: 모두 대문자로 변환 4. 네 번째 문자열: 밑줄을 공백으로 바꾸고 Title Case로 변환

힌트: title(), swapcase(), upper(), lower(), replace() 메서드를 사용하세요.

# 여기에 코드를 작성하세요
strings = [
    "hello world",
    "PYTHON PROGRAMMING",
    "Data Science",
    "machine_learning_basics"
]

문제 4: format() 메서드 활용

다음 데이터를 사용하여 format() 메서드로 여러 형식의 출력을 생성하세요:

name = "Alice Johnson"
age = 28
salary = 75000.50
department = "Engineering"

요구사항:

  1. 위치 인자를 사용한 포맷팅
  2. 키워드 인자를 사용한 포맷팅
  3. 인덱스를 사용한 포맷팅 (같은 값을 여러 번 사용)
  4. 숫자 포맷 지정 (천 단위 구분, 소수점 2자리)

출력 예시:

Employee: Alice Johnson, Age: 28
Department: Engineering, Salary: $75,000.50
Alice Johnson works in Engineering and earns $75,000.50

힌트: “{0}”.format(), “{name}”.format(), “{salary:,.2f}” 형식을 활용하세요.

# 여기에 코드를 작성하세요
name = "Alice Johnson"
age = 28
salary = 75000.50
department = "Engineering"

문제 5: 파일 이름 처리

파일 경로 문자열에서 정보를 추출하고 변환하세요:

file_paths = [
    "/home/user/documents/report.pdf",
    "C:\\Users\\Admin\\Pictures\\photo.jpg",
    "/var/log/system.log",
    "data/files/backup_2024.zip"
]

요구사항:

각 파일 경로에서: 1. 파일 이름만 추출 (확장자 포함) 2. 확장자만 추출 3. 파일 이름 (확장자 제외) 4. 디렉토리 경로만 추출

출력 형식:

파일: report.pdf
  - 확장자: .pdf
  - 이름: report
  - 디렉토리: /home/user/documents

힌트: split(), rsplit(), rfind() 메서드를 활용하세요. os.path 모듈을 사용하지 말고 문자열 메서드만 사용하세요.

# 여기에 코드를 작성하세요
file_paths = [
    "/home/user/documents/report.pdf",
    "C:\\Users\\Admin\\Pictures\\photo.jpg",
    "/var/log/system.log",
    "data/files/backup_2024.zip"
]

문제 6: 텍스트 줄 정렬 및 래핑

긴 텍스트를 특정 너비로 래핑(줄바꿈)하고 정렬하세요:

text = "Python is a high-level, interpreted programming language with dynamic semantics. Its high-level built-in data structures make it very attractive for rapid application development."

요구사항:

  1. 텍스트를 40자 너비로 래핑 (단어 단위로 자르기)
  2. 각 줄을 50자 너비로 가운데 정렬
  3. 각 줄을 50자 너비로 오른쪽 정렬
  4. 총 줄 수 출력

힌트: - 단어를 하나씩 추가하면서 40자를 넘지 않도록 체크 - center(), rjust() 메서드 사용

# 여기에 코드를 작성하세요
text = "Python is a high-level, interpreted programming language with dynamic semantics. Its high-level built-in data structures make it very attractive for rapid application development."

문제 7: 문자열 비교와 정렬

다음 버전 번호 문자열들을 올바른 순서로 정렬하세요:

versions = ["1.10.2", "1.9.0", "2.0.1", "1.9.10", "1.10.0", "2.0.0", "1.9.9"]

요구사항:

  1. 문자열을 그대로 정렬했을 때의 결과 출력
  2. 버전 번호의 의미를 고려한 올바른 정렬 (1.9.0 < 1.9.9 < 1.9.10 < 1.10.0)
  3. 각 버전을 (major, minor, patch) 튜플로 변환하여 정렬

예상 출력:

문자열 정렬: ['1.10.0', '1.10.2', '1.9.0', '1.9.10', '1.9.9', '2.0.0', '2.0.1']
올바른 정렬: ['1.9.0', '1.9.9', '1.9.10', '1.10.0', '1.10.2', '2.0.0', '2.0.1']

힌트: split(‘.’)을 사용하여 각 부분을 분리하고, int()로 변환하여 비교하세요.

# 여기에 코드를 작성하세요
versions = ["1.10.2", "1.9.0", "2.0.1", "1.9.10", "1.10.0", "2.0.0", "1.9.9"]

문제 8: 패스워드 유효성 검증

사용자 패스워드가 다음 조건을 만족하는지 검증하는 함수를 작성하세요:

패스워드 조건: 1. 최소 8자 이상 2. 최소 1개의 대문자 포함 3. 최소 1개의 소문자 포함 4. 최소 1개의 숫자 포함 5. 최소 1개의 특수문자 포함 (!@#$%^&*)

passwords = [
    "Pass123!",      # 유효
    "password",      # 대문자, 숫자, 특수문자 없음
    "PASSWORD123!",  # 소문자 없음
    "Pass!",         # 너무 짧음, 숫자 없음
    "SecureP@ss1"    # 유효
]

출력 형식:

Pass123!: ✓ 유효한 패스워드
password: ✗ 조건 미달 - 대문자, 숫자, 특수문자 필요
...

힌트: 각 조건을 검사하는 함수를 만들고, any() 함수와 문자열 검증 메서드를 활용하세요.

# 여기에 코드를 작성하세요
passwords = [
    "Pass123!",  # 유효
    "password",  # 대문자, 숫자, 특수문자 없음
    "PASSWORD123!",  # 소문자 없음
    "Pass!",  # 너무 짧음, 숫자 없음
    "SecureP@ss1",  # 유효
]

# **패스워드 조건:**
# 1. 최소 8자 이상
# 2. 최소 1개의 대문자 포함
# 3. 최소 1개의 소문자 포함
# 4. 최소 1개의 숫자 포함
# 5. 최소 1개의 특수문자 포함 (!@#$%^&*)
def is_valid_password(password):
    if len(password) < 8:
        return False
    if not any(char.isupper() for char in password):
        return False
    if not any(char.islower() for char in password):
        return False
    if not any(char.isdigit() for char in password):
        return False
    if not any(char in "!@#$%^&*" for char in password):
        return False
    
    return True


for password in passwords:
    print(f"{password}: {'✓' if is_valid_password(password) else '✗'}")
Pass123!: ✓
password: ✗
PASSWORD123!: ✗
Pass!: ✗
SecureP@ss1: ✓

문제 9: 로그 파일 파싱

서버 로그 데이터를 파싱하여 필요한 정보를 추출하세요:

log_data = """
2024-01-15 10:23:45 INFO User login successful - user_id: 12345
2024-01-15 10:24:12 ERROR Database connection failed - timeout: 30s
2024-01-15 10:25:03 WARNING High memory usage - 85%
2024-01-15 10:26:18 INFO User logout - user_id: 12345
2024-01-15 10:27:55 ERROR File not found - path: /data/file.txt
"""

요구사항:

  1. 각 로그 항목을 딕셔너리로 변환
    • 키: timestamp, level, message
  2. ERROR 레벨 로그만 필터링
  3. 각 레벨별 로그 개수 카운트
  4. 가장 최근 로그의 타임스탬프 추출

출력 예시:

전체 로그: 5개
레벨별 통계:
  INFO: 2개
  ERROR: 2개
  WARNING: 1개

ERROR 로그:
  - 2024-01-15 10:24:12: Database connection failed - timeout: 30s
  - 2024-01-15 10:27:55: File not found - path: /data/file.txt

힌트: split(), strip(), startswith() 메서드를 조합하여 사용하세요.

# 로그 파일 파싱 솔루션
log_data = """
2024-01-15 10:23:45 INFO User login successful - user_id: 12345
2024-01-15 10:24:12 ERROR Database connection failed - timeout: 30s
2024-01-15 10:25:03 WARNING High memory usage - 85%
2024-01-15 10:26:18 INFO User logout - user_id: 12345
2024-01-15 10:27:55 ERROR File not found - path: /data/file.txt
"""

# 1. 로그 데이터를 줄 단위로 분리
lines = log_data.strip().split('\n')

# 2. 각 로그 항목을 딕셔너리로 변환
log_entries = []
for line in lines:
    if line.strip():  # 빈 줄 제외
        # 로그 형식: "날짜 시간 레벨 메시지"
        parts = line.split(' ', 3)  # 최대 3번만 분할 (날짜, 시간, 레벨, 나머지)
        
        if len(parts) >= 4:
            timestamp = f"{parts[0]} {parts[1]}"  # 날짜 + 시간
            level = parts[2]
            message = parts[3]
            
            log_entries.append({
                'timestamp': timestamp,
                'level': level,
                'message': message
            })

# 3. 전체 로그 개수
total_logs = len(log_entries)

# 4. 레벨별 로그 개수 카운트
level_counts = {}
for entry in log_entries:
    level = entry['level']
    level_counts[level] = level_counts.get(level, 0) + 1

# 5. ERROR 레벨 로그만 필터링
error_logs = [entry for entry in log_entries if entry['level'] == 'ERROR']

# 6. 가장 최근 로그의 타임스탬프 (마지막 로그)
latest_timestamp = log_entries[-1]['timestamp'] if log_entries else None

# 결과 출력
print(f"전체 로그: {total_logs}개")
print("\n레벨별 통계:")
for level, count in sorted(level_counts.items()):
    print(f"  {level}: {count}개")

print("\nERROR 로그:")
for error in error_logs:
    print(f"  - {error['timestamp']}: {error['message']}")

print(f"\n가장 최근 로그: {latest_timestamp}")

문제 10: CSV 데이터 처리

CSV 형식의 문자열 데이터를 파싱하고 변환하세요:

csv_data = """Name,Age,City,Salary
John Doe,28,Seoul,50000
Jane Smith,32,Busan,65000
Bob Johnson,45,Incheon,75000
Alice Lee,29,Daegu,55000"""

요구사항:

  1. 헤더와 데이터 분리
  2. 각 행을 딕셔너리로 변환
  3. 나이가 30세 이상인 사람만 필터링
  4. 평균 연봉 계산
  5. 도시별 인원 수 카운트

출력 예시:

전체 인원: 4명
30세 이상: 2명 (Jane Smith, Bob Johnson)
평균 연봉: $61,250
도시별 분포: Seoul(1), Busan(1), Incheon(1), Daegu(1)

힌트: split(‘’)으로 줄을 분리하고, split(‘,’)로 각 필드를 분리하세요.

# 여기에 코드를 작성하세요
csv_data = """Name,Age,City,Salary
John Doe,28,Seoul,50000
Jane Smith,32,Busan,65000
Bob Johnson,45,Incheon,75000
Alice Lee,29,Daegu,55000"""

문제 11**: 텍스트 감정 분석기

간단한 감정 분석 함수를 작성하세요. 텍스트의 긍정/부정 점수를 계산합니다.

text = """
I love this product! It's absolutely amazing and works perfectly. 
However, the shipping was terrible and took forever. The customer 
service was unhelpful and rude. But overall, I'm happy with my purchase 
because the quality is excellent.
"""

요구사항:

  1. 긍정 단어 리스트와 부정 단어 리스트 정의
  2. 텍스트에서 각 단어의 출현 횟수 카운트
  3. 감정 점수 계산 (긍정 점수 - 부정 점수)
  4. 문장별로 감정 분석
  5. 전체 감정 판정 (긍정/중립/부정)

긍정 단어: love, amazing, perfectly, happy, excellent, good, great, wonderful
부정 단어: terrible, forever, unhelpful, rude, bad, awful, horrible, worst

출력 예시:

=== 전체 감정 분석 ===
긍정 단어: 4개 (love, amazing, perfectly, happy, excellent)
부정 단어: 3개 (terrible, forever, unhelpful, rude)
감정 점수: +1

문장별 분석:
1. "I love this product!..." → 긍정 (점수: +3)
2. "However, the shipping..." → 부정 (점수: -2)
3. "The customer service..." → 부정 (점수: -2)
4. "But overall, I'm happy..." → 긍정 (점수: +2)

최종 판정: 약한 긍정
def analyze_sentiment(text):
    """
    텍스트의 감정을 분석합니다.
    
    Args:
        text: 분석할 텍스트
    
    Returns:
        dict: 감정 분석 결과
    """
    import string
    
    # 긍정/부정 단어 정의
    positive_words = ['love', 'amazing', 'perfectly', 'happy', 'excellent', 
                      'good', 'great', 'wonderful']
    negative_words = ['terrible', 'forever', 'unhelpful', 'rude', 
                      'bad', 'awful', 'horrible', 'worst']
    
    # 1. 텍스트 정규화 (소문자, 구두점 제거)
    text_clean = text.lower()
    # 힌트: translate()를 사용하여 구두점 제거
    translator = str.maketrans('', '', string.punctuation)
    text_clean = ...
    
    # 2. 단어로 분리
    words = ...
    
    # 3. 긍정/부정 단어 찾기
    found_positive = []  # 힌트: 리스트 컴프리헨션 사용
    found_negative = []
    
    # 4. 감정 점수 계산
    sentiment_score = len(found_positive) - len(found_negative)
    
    # 5. 문장별 분석 (힌트: '.'로 문장 분리)
    sentences = ...
    sentence_sentiments = []
    
    for sentence in sentences:
        if sentence.strip():  # 빈 문장 제외
            # 각 문장의 감정 점수 계산
            pass
    
    # 6. 최종 판정
    if sentiment_score > 2:
        final_verdict = "강한 긍정"
    elif sentiment_score > 0:
        final_verdict = "약한 긍정"
    elif sentiment_score == 0:
        final_verdict = "중립"
    elif sentiment_score > -2:
        final_verdict = "약한 부정"
    else:
        final_verdict = "강한 부정"
    
    # 결과 출력
    print("=== 전체 감정 분석 ===")
    print(f"긍정 단어: {len(found_positive)}개 ({', '.join(found_positive)})")
    print(f"부정 단어: {len(found_negative)}개 ({', '.join(found_negative)})")
    print(f"감정 점수: {sentiment_score:+d}")
    print(f"\n최종 판정: {final_verdict}")
    
    return {
        'positive_count': len(found_positive),
        'negative_count': len(found_negative),
        'score': sentiment_score,
        'verdict': final_verdict
    }

# 테스트
text = """
I love this product! It's absolutely amazing and works perfectly. 
However, the shipping was terrible and took forever. The customer 
service was unhelpful and rude. But overall, I'm happy with my purchase 
because the quality is excellent.
"""

analyze_sentiment(text)

문제 12**: 간단한 마크다운 파서

마크다운 형식의 텍스트를 HTML로 변환하는 간단한 파서를 작성하세요.

지원할 마크다운 문법: 1. # 제목 → <h1>제목</h1> 2. ## 부제목 → <h2>부제목</h2> 3. **굵게** → <strong>굵게</strong> 4. *기울임* → <em>기울임</em> 5. `코드` → <code>코드</code> 6. - 리스트 → <li>리스트</li> (연속된 - 항목은 <ul>로 감싸기)

markdown_text = """
# Python Programming
## Introduction
Python is a **high-level** programming language.
It is *easy* to learn and use.

Key features:
- Simple syntax
- **Powerful** libraries
- Great for `data science`
"""

요구사항:

  1. 각 줄을 파싱하여 해당하는 HTML 태그로 변환
  2. 인라인 스타일 (**, *, `) 처리
  3. 리스트 항목 그룹화
  4. 빈 줄은 <br> 태그로 변환

출력 예시:

<h1>Python Programming</h1>
<h2>Introduction</h2>
<p>Python is a <strong>high-level</strong> programming language.</p>
<p>It is <em>easy</em> to learn and use.</p>
<br>
<p>Key features:</p>
<ul>
<li>Simple syntax</li>
<li><strong>Powerful</strong> libraries</li>
<li>Great for <code>data science</code></li>
</ul>
def markdown_to_html(markdown_text):
    """
    마크다운 텍스트를 HTML로 변환합니다.
    
    Args:
        markdown_text: 마크다운 형식의 텍스트
    
    Returns:
        str: 변환된 HTML 문자열
    """
    
    def process_inline_styles(text):
        """인라인 스타일 처리 (**, *, `)"""
        # 힌트 1: **텍스트** → <strong>텍스트</strong>
        # while "**" in text:
        #     start = text.find("**")
        #     end = text.find("**", start + 2)
        #     ...
        
        # **bold** 처리
        while "**" in text:
            start = text.find("**")
            end = text.find("**", start + 2)
            if end != -1:
                content = text[start+2:end]
                text = text[:start] + f"<strong>{content}</strong>" + text[end+2:]
            else:
                break
        
        # *italic* 처리 (힌트: **과 유사하지만 * 하나만)
        # 코드 작성
        
        # `code` 처리
        # 코드 작성
        
        return text
    
    lines = markdown_text.strip().split('\n')
    html_lines = []
    in_list = False  # 리스트 안에 있는지 추적
    
    for line in lines:
        line = line.strip()
        
        # 빈 줄 처리
        if not line:
            if in_list:
                html_lines.append("</ul>")
                in_list = False
            html_lines.append("<br>")
            continue
        
        # # 헤더 처리 (힌트: startswith()로 #의 개수 확인)
        if line.startswith("# "):
            if in_list:
                html_lines.append("</ul>")
                in_list = False
            content = line[2:]  # "# " 제거
            content = process_inline_styles(content)
            html_lines.append(f"<h1>{content}</h1>")
        
        elif line.startswith("## "):
            # 코드 작성
            pass
        
        # - 리스트 처리
        elif line.startswith("- "):
            if not in_list:
                html_lines.append("<ul>")
                in_list = True
            content = line[2:]  # "- " 제거
            content = process_inline_styles(content)
            html_lines.append(f"<li>{content}</li>")
        
        # 일반 텍스트 (단락)
        else:
            if in_list:
                html_lines.append("</ul>")
                in_list = False
            content = process_inline_styles(line)
            html_lines.append(f"<p>{content}</p>")
    
    # 마지막에 리스트가 열려있으면 닫기
    if in_list:
        html_lines.append("</ul>")
    
    return '\n'.join(html_lines)

# 테스트
markdown_text = """
# Python Programming
## Introduction
Python is a **high-level** programming language.
It is *easy* to learn and use.

Key features:
- Simple syntax
- **Powerful** libraries
- Great for `data science`
"""

html_output = markdown_to_html(markdown_text)
print(html_output)
print("\n=== 렌더링된 형태 (참고) ===")
print("(실제로는 브라우저에서 볼 때 HTML 태그가 적용됩니다)")

This work © 2025 by Sungkyun Cho is licensed under CC BY-NC-SA 4.0