[Baekjoon] 17413/단어 뒤집기 2/Python/파이썬/자료구조/문자열/stack

·2024년 12월 24일
0

문제풀이

목록 보기
8/56
post-thumbnail

💡문제

문자열 S가 주어졌을 때, 이 문자열에서 단어만 뒤집으려고 한다.

먼저, 문자열 S는 아래와과 같은 규칙을 지킨다.

1.알파벳 소문자('a'-'z'), 숫자('0'-'9'), 공백(' '), 특수 문자('<', '>')로만 이루어져 있다.
2.문자열의 시작과 끝은 공백이 아니다.
3.'<'와 '>'가 문자열에 있는 경우 번갈아가면서 등장하며, '<'이 먼저 등장한다. 또, 두 문자의 개수는 같다.

태그는 '<'로 시작해서 '>'로 끝나는 길이가 3 이상인 부분 문자열이고, '<'와 '>' 사이에는 알파벳 소문자와 공백만 있다. 단어는 알파벳 소문자와 숫자로 이루어진 부분 문자열이고, 연속하는 두 단어는 공백 하나로 구분한다. 태그는 단어가 아니며, 태그와 단어 사이에는 공백이 없다.

입력

첫째 줄에 문자열 S가 주어진다. S의 길이는 100,000 이하이다.

출력

첫째 줄에 문자열 S의 단어를 뒤집어서 출력한다.

예제입력

baekjoon online judge

예제출력

noojkeab enilno egduj

📖내가 작성한 Code

import re


def flip(data):
    if data[0] == '<':
        return data
    sentence = []
    for word in data.split():
        sentence.append(word[::-1])
    return ' '.join(sentence)


def main():
    result = []
    for sentence in re.split(r'(<[^>]*>)', input()):
        if len(sentence):
            result.append(flip(sentence))
    return ''.join(result)


if __name__ == "__main__":
    print(main())

✍️풀이과정

위의 코드처럼 그냥 분기를 나누어 해결하려 하였음. 처음에는 split()를 사용하여 띄어쓰기 먼저 분리하니까 tag 안에 것도 분리 되길래, 처음으로 정규식을 사용해봤음.

re.split

  • re에서 제공하는 문자열 분할 함수
  • re.split(패턴,문자열,maxsplit)
  • 여러 기호 동시에 사용하고 싶다면 대괄호 이용
  • 캡처 그룹((...)) 사용시 자체 결과도 리스트에 포함

re.split(r'(<[^>]*>)', input()) 의 의미

  • input()으로 받은 문자열을 r 이하로 파싱하여 list로 나타내겠다.
  • r이하는 다음과 같다.
1. (...) 캡처 그룹을 사용해 통째로 문자열 취급 하겠다.
2. '<'를 찾아서 시작점으로 사용한다.
3. [^>]* >가 아닌 모든 문자(^(not) 사용) 모든 문자열을 *(0번 이상 반복)하여 넣겠다.
4. '>'가 나오면 종료한다.

하지만, 나중에 알게 된 사실인데 그냥 stack문제라서 당황하긴 했는데 python이라 ㅎㅎ...
이렇게 하면 공백(스페이스) 보존 문제로 틀릴 경우가 발생한다고 함.


🧠 코드 리뷰

  1. 공백(스페이스) 보존 문제 : 현재 코드는 data.split() -> word[::-1] -> ' '.join(...) 로 처리하기 때문에,여러 칸 공백이 있으면 전부 단일 공백으로 합쳐짐. 따라서 문자를 하나씩 훑으면서 진행할 필요가 있음

  2. 태그 판정 로직 : 사실상 정규식 (<[^>]*>)에서 분리된 data가 태그라면 <부터 >까지를 전부 포함하므로, if data.startswith('<'):처럼 좀 더 의도가 명확한 조건을 사용하면 좋음

  3. 성능 측면 : 입력 문자열 길이가 매우 길 경우(N이 큰 경우), re.split의 성능이 걱정되는 사람도 있을 수 있지만, 실제로는 파이썬 내장 정규표현 엔진이 꽤 빠르기 때문에, 보통은 큰 문제는 없음.


🛠️AI 개선 코드

import re

def flip_text_preserving_whitespace(text: str) -> str:
    """
    태그 밖 문자열을 뒤집을 때에도 원본에 포함된 공백 개수를 그대로 유지하도록,
    문자 단위로 처리하며 단어(연속된 비공백)만 뒤집는다.
    """
    result = []
    word_buffer = []

    for char in text:
        if char.isspace():
            # 현재까지 누적된 word_buffer(연속된 비공백)는 뒤집어 추가하고 비운다.
            if word_buffer:
                result.append(''.join(reversed(word_buffer)))
                word_buffer.clear()
            # 공백 자체는 그대로 결과에 추가한다.
            result.append(char)
        else:
            # 공백이 아니면 단어 버퍼에 쌓는다.
            word_buffer.append(char)

    # 마지막으로 버퍼에 남은 단어가 있으면 뒤집어 추가한다.
    if word_buffer:
        result.append(''.join(reversed(word_buffer)))

    return ''.join(result)


def main():
    # 전체 문자열 입력
    text = input()

    # 정규식으로 "<...>" 태그와 그 외 부분을 분리
    tokens = re.split(r'(<[^>]*>)', text)

    result = []
    for token in tokens:
        # 빈 문자열이면 건너뛰기
        if not token:
            continue
        
        # token이 태그인지, 태그가 아닌지 구분
        if token.startswith('<') and token.endswith('>'):
            # 태그라면 그대로 추가
            result.append(token)
        else:
            # 태그 밖의 문자열이므로, 공백을 그대로 유지하며 단어만 뒤집기
            flipped = flip_text_preserving_whitespace(token)
            result.append(flipped)

    # 전체 결과를 합쳐 출력
    print(''.join(result))


if __name__ == "__main__":
    main()

💻결과

백준문제 보러가기


🖱️참고 링크

자료구조 Python 공식문서

profile
우물 안에서 무언가 만드는 사람

0개의 댓글