PS/백준

[백준] (31024) Filesystem [Python]

munsik22 2025. 10. 25. 17:43

문제 링크

https://www.acmicpc.net/problem/31024

문제

파일 시스템 명령어와 쿼리가 주어질 때, 각 쿼리가 요청하는 파일의 내용을 출력해야 한다. 만약 쿼리가 유효하지 않으면(예: 경로가 존재하지 않는 경우) invalid! 를 출력해야 한다.

다음 명령어들을 지원해야 한다.

지원 명령어

echo "<content>" > <path>

  • <path> 파일에 <content>를 쓴다.
  • 만약 <path>가 이미 존재한다면, 그것은 파일이어야 하며 내용은 덮어쓰인다.
  • 경로가 존재하지 않는다면, 부모 디렉터리는 반드시 존재해야 하며, 이 경우 파일이 새로 생성된다.
  • <content>는 ASCII 숫자, 문자, *, ?, <, >, 그리고 공백만을 포함한다.

cp <source> <destination>

  • <source> 파일을 <destination> 파일 또는 디렉터리로 복사한다.
  • 만약 <destination>이 이미 존재하는 디렉터리라면, 파일은 <destination> 디렉터리 안으로 복사되며, 파일명은 <source> 경로의 마지막 부분이 된다.
  • 그렇지 않다면, <destination>이 새로운 파일명이 되며, 이 경우 <destination>의 부모 디렉터리는 반드시 존재해야 한다.
  • 새 파일은 기존의 내용을 덮어쓴다.

mv <source> <destination>

  • 파일 또는 디렉터리 <source><destination> 파일 또는 디렉터리로 이동시킨다.
  • cp와 유사하게, <destination>이 이미 존재하는 디렉터리라면, 소스 파일/디렉터리는 <destination> 디렉터리 안으로 이동한다. 이때 이름은 <source> 경로의 마지막 부분과 동일하다.
  • 그렇지 않다면, <destination>이 새로운 파일명이 되며, 부모 디렉터리는 반드시 존재해야 한다.
  • 새 파일은 기존 내용을 덮어쓰고, <source>는 삭제된다.

rm <path>

  • <path> 경로의 파일을 삭제한다.

mkdir <path>

  • <path> 경로에 디렉터리를 생성한다. 부모 디렉터리는 반드시 존재해야 한다.

rmdir <path>

  • <path> 경로의 비어있는 디렉터리를 삭제한다.

※ 참고:

  • 모든 파일 시스템 경로는 숫자, 문자, 또는 /만을 포함하며, 길이는 31자 또는 7개의 경로 구성 요소를 초과하지 않는다.
  • 경로 구성 요소는 /로 구분된다.
  • 입력으로 주어지는 모든 명령어는 유효하며, 위에서 명시된 경우를 제외하고는 존재하지 않거나 유효하지 않은 경로를 참조하지 않는다.
  • 모든 명령어는 1024자 미만이다.

입력

  • 첫 번째 줄에 테스트 케이스의 수를 나타내는 T (0 < T < 100)가 주어진다.
  • 다음 줄에 해당 테스트 케이스의 명령어 수를 나타내는 C (0 < C < 100)가 주어진다.
  • 이어지는 C개의 줄에 파일 시스템을 구성하는 명령어가 주어진다.
  • 파일 시스템이 시작되는 폴더는 무시해도 된다. 즉, 현재 디렉터리(./)로 가정할 수 있다.
  • 다음 줄에 내용을 출력해야 할 파일명의 수를 나타내는 Q (0 < Q < 20)가 주어진다.
  • 이어지는 Q개의 줄에 내용을 출력할 파일명 (또는 myfolder/myfile과 같은 경로 및 파일명)이 주어진다.

출력

  • 쿼리가 요청하는 파일의 내용을 출력하거나, 파일이 존재하지 않으면 "invalid!"를 출력한다.
  • 각 테스트 케이스가 끝난 후에는 빈 줄을 하나 출력한다.

코드

더보기
from collections import deque
from re import findall

def split_str(s):
    items = findall(r'"[^"]+"|\S+', s)
    result = []
    for item in items:
        if item.startswith('"') and item.endswith('"'):
            result.append(item[1:-1])
        else:
            result.append(item)
    return result

class File:
    def __init__(self, name, content, directory=None):
        self.name = name
        self.content = content
        self.directory = directory
    def update_content(self, content):
        self.content = content

class Folder:
    def __init__(self, name, parent=None):
        self.name = name
        self.parent = parent
        self.child = dict()
        self.files = dict()
    def add_child(self, child):
        self.child[child.name] = child
        child.parent = self
    def remove_child(self, child):
        self.child.pop(child.name)
        child.parent = None
    def add_file(self, file):
        self.files[file.name] = file
        file.directory = self
    def remove_file(self, file):
        self.files.pop(file.name)
        file.directory = None

T = int(input())
for t in range(T):
    root = Folder('')
    c = int(input())
    for _ in range(c):
        cmd = split_str(input())
        if cmd[0] == "echo":
            content = cmd[1]
            path = deque(cmd[-1].split('/'))
            cur = root
            
            while len(path) > 1:
                cur = cur.child[path.popleft()]
            
            if path[0] in cur.files:
                cur.files[path[0]].update_content(content)
            else:
                new_file = File(path[0], content)
                cur.add_file(new_file)
        
        elif cmd[0] == "cp":
            s_path = deque(cmd[1].split('/'))
            d_path = deque(cmd[2].split('/'))
            
            cur = root
            while len(s_path) > 1:
                cur = cur.child[s_path.popleft()]
            target = cur.files[s_path[0]]
            
            cur = root
            while len(d_path) > 1:
                cur = cur.child[d_path.popleft()]
                
            if d_path[0] in cur.child: # destination is a directory
                cur = cur.child[d_path[0]]
                new_file = File(target.name, target.content)
            else: # destination is a new filename
                new_file = File(d_path[0], target.content)
            cur.add_file(new_file)
        
        elif cmd[0] == "mv":
            s_path = deque(cmd[1].split('/'))
            d_path = deque(cmd[2].split('/'))
            
            cur = root
            while len(s_path) > 1:
                cur = cur.child[s_path.popleft()]
                
            is_file = True
            if s_path[0] in cur.files:
                target = cur.files[s_path[0]]
            else:
                target = cur.child[s_path[0]]
                is_file = False
            
            cur = root
            while len(d_path) > 1:
                cur = cur.child[d_path.popleft()]
            
            if d_path[0] in cur.child: # destination is a directory
                cur = cur.child[d_path[0]]
                if is_file:
                    new_file = File(target.name, target.content)
                    cur.add_file(new_file)
                    target.directory.remove_file(target)
                else:
                    target.parent.remove_child(target)
                    cur.add_child(target)
            else: # destination is a new filename
                new_file = File(d_path[0], target.content)
                cur.add_file(new_file)
                target.directory.remove_file(target)

        elif cmd[0] == "rm":
            paths = deque(cmd[1].split('/'))
            cur = root
            while len(paths) > 1:
                cur = cur.child[paths.popleft()]
            cur.remove_file(cur.files[paths[0]])

        elif cmd[0] == "mkdir":
            paths = deque(cmd[1].split('/'))
            cur = root
            while len(paths) > 1:
                cur = cur.child[paths.popleft()]
            new_child = Folder(paths[0])
            cur.add_child(new_child)

        elif cmd[0] == "rmdir":
            paths = deque(cmd[1].split('/'))
            cur = root
            while len(paths) > 1:
                cur = cur.child[paths.popleft()]
            cur.remove_child(cur.child[paths[0]])

    q = int(input())
    res = list()
    is_error = False
    for _ in range(q):
        cmd = deque(input().split('/'))
        try:
            cur = root
            while len(cmd) > 1:
                cur = cur.child[cmd.popleft()]
            res.append(cur.files[cmd[0]].content)
        except:
            is_error = True
            break
    if is_error:
        print("invalid!")
    else:
        for r in res:
            print(r)
    if t != T-1:
        print()