← 기술 블로그 목록으로 돌아가기
#946 • File Governance & Reversible Batch Automation Architecture

학생 과제물 100개 0초 일괄 정리와 소실 방지: ZeliRename의 정규식(Regex) 배치 리네이머와 Undo 스택 가역 복원 아키텍처

"학생 100명이 제각각 제출한 수행평가 파일 이름을 학번_이름_과목 규칙으로 일일이 F2 키를 눌러 바꾸다 2시간을 낭비하거나, 잘못 변경하여 원본 이름을 잃어버린 적이 있으십니까?" 윈도우 탐색기의 무의미한 괄호 넘버링과 상용 리네이머의 라이선스 단속을 종식시키는 Zero-Install 온디바이스 배치 파일 거버넌스 스위트, 5대 리네이밍 규칙(찾아바꾸기·접두사/접미사·시퀀스 넘버링·대소문자·정규식 Regex) 실시간 파이프라인, Path.GetInvalidFileNameChars 금지 문자 사전 차단, 동일 경로 덮어쓰기 방지 알고리즘, 그리고 Stack<List<(Old, New)>> 기반의 100% 안전한 원클릭 가역적 언두(Undo) 복원 아키텍처 백서.

"학기 말 수행평가 기간이 되면 교사들의 컴퓨터 바탕화면은 수백 개의 파일로 뒤덮입니다. 학생들은 '1반 3번 홍길동.hwp', '수행평가.docx', '새 파일 (1).pdf', '이것이최종.pptx' 등 제멋대로 이름을 붙여 제출합니다. 이를 출석번호 순으로 정렬하기 위해 윈도우 탐색기에서 전체를 선택하고 이름을 바꾸면 '과제 (1)', '과제 (2)'처럼 학생 이름이 모두 지워지는 대참사가 일어납니다. 유명 공개 소프트웨어(DarkNamer 등)는 10년 넘게 업데이트가 중단되었고 되돌리기(Undo)가 없어 교사의 실수를 복구하지 못합니다. ZeliRename은 단 1바이트의 외부 바이너리 없이, 실시간 미리보기와 정규식 치환을 거쳐 단 0초 만에 완벽한 이름으로 변환하며 언제든 원본 이름으로 되돌릴 수 있는 완벽한 가역 안전망을 제공합니다."

1. 학교 전산실과 교무실의 파일명 대혼란: "제각각 제출된 100개 과제물과 괄호 넘버링의 악몽"

공교육과 군부대 행정 실무에서 수십~수백 개의 파일을 체계적으로 관리하는 일은 업무 시간의 상당 부분을 소모하는 고된 작업입니다:

2. 윈도우 파일 탐색기 및 단종된 레거시 리네이머의 한계: "규칙 부재와 되돌리기(Undo) 없는 영구 소실 공포"

Windows 파일 탐색기와 인터넷에서 다운로드받는 구형 유틸리티들은 안전성 면에서 치명적인 결함을 가지고 있습니다:

  1. 탐색기 다중 이름 바꾸기의 원본 파괴: 파일 여러 개를 선택하고 F2 키를 누르면 모든 파일의 고유 이름이 사라지고 오직 `지정한이름 (1).ext`, `지정한이름 (2).ext`로 덮어써집니다.
  2. 실시간 미리보기(Live Preview)의 부재: 버튼을 누르기 전까지 파일명이 어떻게 바뀔지 시각적으로 검증할 수 없어 오탈자나 정규식 실수 시 파일 시스템이 영구히 훼손됩니다.
  3. 되돌리기(Undo) 기능 미지원: 과거의 셰어웨어 프로그램들은 파일 이동/리네임 후 이전 파일명 히스토리를 메모리에 보관하지 않아, 실수를 인지했을 때 수백 개 파일의 원본을 영원히 찾을 수 없습니다.
flowchart TD subgraph INPUT["📂 파일 / 폴더 대량 유입"] F1["FileOpenPicker (다중 파일 선택)"] F2["FolderPicker (폴더 내 전체 파일 순회)"] F1 & F2 --> RAW["_filePaths 원본 경로 수집 (100+ 파일)"] end subgraph ENGINE["⚙️ 5대 리네이밍 규칙 변환 & 실시간 미리보기"] RAW --> R0["Mode 0: 찾아 바꾸기 (Replace)"] RAW --> R1["Mode 1: 접두사/접미사 (Prefix/Suffix)"] RAW --> R2["Mode 2: 시퀀스 번호 (file_###)"] RAW --> R3["Mode 3: 대소문자 변환 (Lower/Upper/Title)"] RAW --> R4["Mode 4: 정규식 (Regex 캡처 그룹 치환)"] R0 & R1 & R2 & R3 & R4 --> CHK["Path.GetInvalidFileNameChars 금지 문자 검사"] CHK -->|유효한 이름| PREVIEW["_previews 컬렉션 렌더링 (Original vs New)"] CHK -->|금지 문자 검출| WARN["⚠️ 에러 표기 및 실행 버튼(BtnApply) 비활성화"] end subgraph EXEC["🛡️ 원자적 파일 변경 & Undo 스택 가역 복원"] PREVIEW -->|BtnApply 클릭| EXIST["File.Exists(newPath) 중복 충돌 검증"] EXIST -->|충돌 없음| MOVE["File.Move(oldPath, newPath) 원자적 실행"] MOVE --> STACK["_undoStack.Push(newPath, oldPath) 가역 캐싱"] STACK -->|실수 발생 시 BtnUndo 클릭| ROLLBACK["File.Move(currentPath, originalPath) 100% 완벽 복구"] end classDef input fill:#0f172a,stroke:#38bdf8,stroke-width:2px,color:#bae6fd; classDef engine fill:#1e1b4b,stroke:#818cf8,stroke-width:2px,color:#e0e7ff; classDef exec fill:#022c22,stroke:#14b8a6,stroke-width:2px,color:#99f6e4; class INPUT input; class ENGINE engine; class EXEC exec;

3. 5대 리네이밍 규칙 엔진: 찾아바꾸기·접두접미·시퀀스(#)·대소문자·정규식(Regex)

ZeliRename은 교육 현장과 개발 환경에서 발생하는 모든 파일명 변경 요구를 단 5가지 모드로 완벽히 수용합니다:

C# ZeliRename/Views/ZeliRenameWindow.xaml.cs — 5대 모드 변환 로직
switch (CmbMode.SelectedIndex)
{
    case 0: // 1) 찾아 바꾸기
        string find = TxtFind?.Text ?? "";
        string replace = TxtReplaceTo?.Text ?? "";
        if (!string.IsNullOrEmpty(find))
            newName = originalName.Replace(find, replace, StringComparison.OrdinalIgnoreCase);
        break;

    case 1: // 2) 접두사 / 접미사
        string prefix = TxtPrefix?.Text ?? "";
        string suffix = TxtSuffix?.Text ?? "";
        newName = prefix + nameWithoutExt + suffix + ext;
        break;

    case 2: // 3) 시퀀스 번호 (# 개수 기반 자릿수 패딩)
        string pattern = TxtSeqPattern?.Text ?? "file_###";
        int hashCount = pattern.Count(c => c == '#');
        if (hashCount > 0)
        {
            string numStr = seq.ToString().PadLeft(hashCount, '0');
            newName = pattern.Replace(new string('#', hashCount), numStr) + ext;
            seq++;
        }
        break;

    case 3: // 4) 대소문자 변환
        int caseMode = CmbCase?.SelectedIndex ?? 0;
        newName = caseMode switch
        {
            0 => originalName.ToLowerInvariant(),
            1 => originalName.ToUpperInvariant(),
            2 => string.IsNullOrEmpty(nameWithoutExt)
                ? originalName
                : char.ToUpper(nameWithoutExt[0]) + nameWithoutExt.Substring(1).ToLower() + ext.ToLower(),
            _ => originalName
        };
        break;

    case 4: // 5) 정규표현식 치환
        string regexPattern = TxtRegexPattern?.Text ?? "";
        string regexReplace = TxtRegexReplace?.Text ?? "";
        if (!string.IsNullOrEmpty(regexPattern))
        {
            try
            {
                newName = Regex.Replace(originalName, regexPattern, regexReplace, RegexOptions.IgnoreCase);
            }
            catch { newName = originalName; }
        }
        break;
}

4. 실시간 병렬 미리보기와 Path.GetInvalidFileNameChars 금지 문자 안전 방어벽

Windows 파일 시스템(NTFS/FAT32)에서는 \ / : * ? " < > | 등의 특수 문자를 파일 이름에 사용할 수 없습니다. 사용자가 치환 문자열에 실수로 콜론(`:`)이나 슬래시(`/`)를 넣는 순간 운영체제 레벨에서 치명적인 I/O 예외가 발생합니다.

ZeliRename은 Path.GetInvalidFileNameChars()를 실시간으로 대조하여 금지 문자가 발견되면 즉각 경고 라벨(⚠️)을 띄우고 **실행 버튼(BtnApply)을 원천 차단**하여 파일 시스템 크래시를 사전 방어합니다:

C# ZeliRename/Views/ZeliRenameWindow.xaml.cs — 금지 문자 실시간 검증
// 윈도우 금지 문자 검사 (\ / : * ? " < > |)
if (newName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
{
    newName = "⚠️ " + newName + " " + Loc.Get("Rename_InvalidChars");
    BtnApply.IsEnabled = false; // 실행 차단
}

_previews.Add(new RenamePreviewItem
{
    OriginalName = originalName,
    NewName = newName,
    FullPath = path
});

// 모든 미리보기가 정상일 때만 실행 버튼 활성화
if (_previews.All(p => !p.NewName.StartsWith("⚠️")))
{
    BtnApply.IsEnabled = true;
}

5. File.Exists 사전 검사 기반의 파일 덮어쓰기 및 충돌 원천 방지 알고리즘

배치 리네이밍 중 가장 끔찍한 사고는 **서로 다른 두 파일이 동일한 새 이름을 갖게 되는 충돌(Name Collision)**입니다. 예를 들어 시퀀스 규칙을 잘못 적용하여 이미 존재하는 파일명으로 변경을 시도하면, 기존 파일이 영구히 덮어써져 삭제될 위험이 있습니다.

ZeliRename은 File.Move를 실행하기 직전에 타겟 경로에 이미 파일이 존재하는지(File.Exists(newPath))를 선행 검사하여, 충돌이 감지되면 해당 파일의 수정을 안전하게 스킵하고 에러 카운트로 격리합니다:

C# ZeliRename/Views/ZeliRenameWindow.xaml.cs — 덮어쓰기 충돌 격리
string dir = Path.GetDirectoryName(item.FullPath);
string newPath = Path.Combine(dir, item.NewName);

try
{
    // 동일한 이름의 파일이 이미 존재하는 경우 덮어쓰기 방지를 위해 즉시 스킵
    if (File.Exists(newPath))
    {
        errorCount++;
        continue;
    }
    
    File.Move(item.FullPath, newPath);
    undoBatch.Add((newPath, item.FullPath)); // Undo용 (신규경로, 원래경로) 페어 기록
    successCount++;
}
catch
{
    errorCount++;
}

6. Stack<List<(Old, New)>> 가역적 원클릭 언두(Undo) 영속화 파이프라인

"아차, 1반 과제인데 2반으로 잘못 바꿨다!" 이 순간 교사나 행정 실무자는 패닉에 빠집니다. 수백 개 파일의 원래 이름을 기억해 낼 방법이 없기 때문입니다.

ZeliRename은 메모리 기반의 배치 언두 스택(Undo Stack)을 탑재하여 완벽한 가역성을 보장합니다. 실행이 성공한 모든 파일의 `(현재 경로, 원래 경로)` 튜플 리스트를 _undoStack.Push(undoBatch)에 영속화하며, 되돌리기(Undo) 버튼을 누르면 단 0초 만에 모든 파일이 100% 원래의 파일명으로 원상 복구됩니다:

C# ZeliRename/Views/ZeliRenameWindow.xaml.cs — 가역적 원클릭 언두(Undo) 파이프라인
private void BtnUndo_Click(object sender, RoutedEventArgs e)
{
    if (_undoStack.Count == 0) return;

    // 가장 최근 실행 배치 팝(Pop)
    var batch = _undoStack.Pop();
    int restored = 0;

    foreach (var (currentPath, originalPath) in batch)
    {
        try
        {
            // 현재 파일이 존재하고, 원래 이름의 위치가 비어 있을 때만 완벽 복원
            if (File.Exists(currentPath) && !File.Exists(originalPath))
            {
                File.Move(currentPath, originalPath);
                restored++;
            }
        }
        catch { }
    }

    if (_undoStack.Count == 0)
        BtnUndo.Visibility = Visibility.Collapsed;

    // 현재 작업 목록도 복원된 원래 경로로 재동기화
    _filePaths.Clear();
    foreach (var (_, originalPath) in batch)
    {
        if (File.Exists(originalPath)) _filePaths.Add(originalPath);
    }

    TxtStatus.Text = string.Format(Loc.Get("Rename_UndoComplete"), restored);
    RefreshPreview();
}

7. 파일 일괄 변경 도구(Windows 탐색기 vs DarkNamer vs PowerToys PowerRename vs ZeliRename) 비교 분석

공교육 및 공공 기관의 실무 환경에서 기존 솔루션들과 비교한 기술 분석 결과는 다음과 같습니다:

비교 항목 Windows 파일 탐색기 DarkNamer (구형 셰어웨어) MS PowerToys PowerRename ZeliRename (온디바이스)
배포 및 설치 방식 OS 내장 단일 실행 파일 수백 MB 설치 패키지 (UAC 필수) Zero-Install 무설치 네이티브 C#
규칙 다양성 괄호 넘버링 (1), (2) 단일 문자열 자르기/붙이기 정규식 중심 (초보자 어려움) 5대 모드 (초보자부터 정규식까지)
금지 문자 사전 검증 미지원 (오류 팝업) 일부 지원 지원 Path.GetInvalidFileNameChars 차단
가역적 언두(Undo) 복원 Ctrl+Z (불안정/일부 누락) 미지원 (실수 시 복구 불가) 미지원 Stack 기반 100% 원클릭 Undo
덮어쓰기 충돌 방지 (1) 자동 붙임 에러 발생 후 중단 옵션 제공 File.Exists 사전 검사로 안전 스킵
소프트웨어 라이선스 안전 무관 개발 중단 (보안 취약점) 오픈소스 완전 무상 보급 / 100% 라이선스 프리

8. 결론: "상용 라이선스 단속과 과제물 유실 위험 없는 공교육·행정 현장의 필수 온디바이스 유틸리티"

파일을 정리하는 데 필요한 것은 복잡한 스크립트나 무거운 외부 프로그램이 아닙니다. 교사와 공공 실무자에게 진정으로 필요한 것은 "내 소중한 파일이 어떻게 바뀔지 한눈에 보이고, 설령 실수하더라도 단 한 번의 클릭으로 되돌릴 수 있다는 확신"입니다.

ZeliDesk의 ZeliRename은 가장 직관적인 5대 규칙과 철저한 금지 문자 방어벽, 그리고 스택 기반의 가역적 언두 엔진을 통해 파일 일괄 정리의 모든 불안 요소를 제거했습니다. 이제 전국의 선생님들과 국방·공공 실무자들은 과제물 정리에 낭비되던 소중한 시간을 절약하고 교육과 본연의 임무에 더욱 집중할 수 있습니다.

← 이전 기술 백서 #947 전산실 좀비 프로세스와 백그라운드 서비스 교착(Deadlock) 0초 해결: ZeliService의 WMI Win32_Service 비동기 수집과 sc.exe UAC 승격 거버넌스 아키텍처 다음 기술 백서 → #945 SW 수업 깃(Git) 실습 파괴 사고와 강제 푸시 0초 차단: ZeliGit의 UTF-8 비동기 프로세스 스트리밍과 파괴적 명령(push/reset/clean) 안전 방어벽 아키텍처
🏷️ ZeliDesk ZeliRename 온디바이스 파일 리네이머 체험하기
100개 과제물을 0초 만에 정리하고, 언제든 안심하고 Undo로 되돌리세요.
72종 유틸리티 전체 둘러보기 →