MaskedTextBox 를 레거시와 동일하게 프롬프트 문자로 표시
4단계 육안 대조에서 발견한 차이. 마스크 패턴을 그대로 그려서 값이 이미 입력된 것처럼 보였다.
레거시 ___년 __월 __일 (프롬프트 문자)
SheetMe 0000년 90월 90일 (마스크 패턴 원문)
저장 데이터와는 무관한 표시 문제지만, 운영 실사용이 MaskedTextBox 475개 / Mask 보유 460개라
자주 눈에 띈다.
LegacyMask.ToPromptDisplay 신설(Core, 순수 함수) — 입력 자리 지시자는 프롬프트 문자로,
리터럴은 그대로, 이스케이프(\)는 다음 문자를 리터럴로, 대소문자 변환자(< > |)는 표시하지 않는다.
활성 디자인 전수 census 로 지원 범위를 정했다: 등장 지시자는 0(2,675) 9(687) #(12) 와
이스케이프 \(2) 뿐이고 문자류(L ? & C A a)와 변환자는 쓰이지 않는다. PromptChar 속성을 가진
컨트롤은 0개라 전부 기본값 '_' 이지만, 속성이 있으면 반영하도록 구현했다.
구분자 . , : / $ 는 WinForms 가 문화권 구분자로 치환하지만 원문 그대로 둔다 —
운영 마스크는 보이는 대로 쓰이고 레거시 화면도 그렇게 나온다.
MaskDisplay 는 표시 전용 파생 속성이라 PropBag 에 아무것도 쓰지 않는다(왕복 무손실 유지).
인스펙터 편집용 Mask 원문 속성은 그대로 둔다.
검증: 테스트 98/98(마스크 28건 추가 — 운영 실사용 마스크 10종, 이스케이프, 문자류 지시자,
변환자, PromptChar 지정, 끝 백슬래시, 표시 길이 보존). S481 재렌더로 레거시와 동일 표시 확인.
edit-smoke 실패 0, 왕복 1,271건 diff 0/예외 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d1e488625e
commit
a749e18e7b
@@ -0,0 +1,78 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SheetMe.Core.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// WinForms MaskedTextBox 마스크를 <b>화면 표시 문자열</b>로 변환한다.
|
||||
///
|
||||
/// 레거시는 마스크 패턴을 그대로 그리지 않고, 입력 자리마다 프롬프트 문자(기본 <c>_</c>)를 찍고
|
||||
/// 리터럴은 그대로 둔다. 예: <c>0000년 90월 90일</c> → <c>____년 __월 __일</c>.
|
||||
/// 마스크 원문을 그대로 보여주면 디자이너가 값이 이미 입력된 것으로 오해한다.
|
||||
///
|
||||
/// 운영 실측(활성 디자인 전수): MaskedTextBox 475개 / Mask 보유 460개 / 고유 44종.
|
||||
/// 등장 지시자는 <c>0</c>(2,675) <c>9</c>(687) <c>#</c>(12) 와 이스케이프 <c>\</c>(2) 뿐이고
|
||||
/// 문자류 지시자(L/?/&/C/A/a)와 대소문자 변환자(< > |)는 쓰이지 않는다.
|
||||
/// PromptChar 속성을 가진 컨트롤은 0개라 전부 기본값이다. 그래도 전 지시자를 구현해 둔다.
|
||||
/// </summary>
|
||||
public static class LegacyMask
|
||||
{
|
||||
#region Member Fields
|
||||
/// <summary>WinForms 기본 프롬프트 문자</summary>
|
||||
public const char DefaultPromptChar = '_';
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>
|
||||
/// 마스크 → 표시 문자열. 입력 자리는 <paramref name="promptChar"/>, 그 외는 리터럴로 남긴다.
|
||||
/// </summary>
|
||||
/// <param name="mask">레거시 Mask 속성 값</param>
|
||||
/// <param name="promptChar">프롬프트 문자 — 레거시 PromptChar 속성(기본 <c>_</c>)</param>
|
||||
public static string ToPromptDisplay(string? mask, char promptChar = DefaultPromptChar)
|
||||
{
|
||||
if (string.IsNullOrEmpty(mask))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var result = new StringBuilder(mask.Length);
|
||||
for (var i = 0; i < mask.Length; i++)
|
||||
{
|
||||
var c = mask[i];
|
||||
switch (c)
|
||||
{
|
||||
// 이스케이프 — 다음 문자를 리터럴로. 마스크 끝에 홀로 오면 리터럴 백슬래시로 둔다.
|
||||
case '\\':
|
||||
if (i + 1 < mask.Length)
|
||||
{
|
||||
result.Append(mask[++i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Append(c);
|
||||
}
|
||||
break;
|
||||
|
||||
// 입력 자리 지시자 — 숫자/문자/영숫자 계열 모두 한 자리를 소비한다
|
||||
case '0' or '9' or '#' // 숫자 계열
|
||||
or 'L' or '?' // 문자 계열
|
||||
or '&' or 'C' // 임의 문자 계열
|
||||
or 'A' or 'a': // 영숫자 계열
|
||||
result.Append(promptChar);
|
||||
break;
|
||||
|
||||
// 대소문자 변환자 — 자리를 차지하지 않고 표시에도 나타나지 않는다
|
||||
case '<' or '>' or '|':
|
||||
break;
|
||||
|
||||
// 그 외(구분자 . , : / $ 와 한글·공백 등)는 리터럴.
|
||||
// WinForms 는 . , : / $ 를 문화권 구분자로 치환하지만, 운영 마스크는 보이는 그대로
|
||||
// 쓰이고 레거시 화면도 그렇게 나오므로 원문을 유지한다.
|
||||
default:
|
||||
result.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user