본문 바로가기
C#

[C#] 표준 서식 문자열과 파싱 플래그

by DANEW 2023. 8. 13.

:: 포맷팅 ::

수치 서식 문자열

G : 일반(지수 표기 대문자)

g : 일반(지수 표기 소문자)

F : 고정 소수점

N : 그룹 구분자가 있는 고정 소수점

D : 선행 자리수를 0으로 채움

E : 지수 표기(대문자)

e : 지수 표기(소문자)

C : 통화

P : 퍼센트

X : 16진수(대문자)

x : 16진수(소문자)

R : 순환소수(복원 가능)

 * float이나 double의 정밀도 한계에 놓인 두 유효숫자는 버려지나, R이나 G17은 버리지 않는다.

 * .NET 4.6 이상에서 R과 G17은 같은 일을 함.

 * 그 이전 버전에서는 R은 G17의 버그 있는 버전이므로 사용 하지 말 것.

 

커스텀 수치 서식 문자열

# : 숫자 자리표, 소수점 이하 자릿수를 #수만큼 제한함

0 : 0 자리표, 소수점 이전과 이후의 빈 자리에 0들을 채움.

. : 소수점

, : 그룹 구분자(ex: #,###,###)

, : 승수(ex: #,,), 1000이나 1000000등으로 나눈 결과

% : 퍼센트 표기, 100을 곱하고 퍼센트 기호를 붙힘

E0, e0, E+0, e+0, E-0, e-0: 지수 표기

\ : 리터럴 문자 인용, @ 접두사가 없는 문장에서는 \\

' ' : 리터럴 문자열 인용

; : 섹션 구분자

 

:: 파싱 ::

NumberStyles 열거형

(System.Globalization.Numberstyle)

 

- 플래그 열거형(Flags 특성이 지정된 enum)

- 문자열을 수치 형식으로 변환할 때 적용되는 규칙들을 지정

 

1. 일반 멤버

 - AllowLeadingWhite: 앞쪽에 일련의 공백이 올 수 있음

 - AllowTrailingWhite: 뒤쪽에 일련의 공백이 올 수 있음

  [ 인식하는 공백 문자, IsWhiteSpace가 true를 반환하는 문자 집단의 부분집합 ]

  * CHARACTER TABULATION (U+0009)

  * LINE FEED (U+000A)

  * LINE TABULATION (U+000B)

  * FORM FEED (U+000C)

  * CARRIAGE RETURN (U+000D)

  * SPACE (U+0020)

 

 - AllowLeadingSign: 앞쪽에 부호 문자가 올 수 있음

 - AllowTrailingSign: 뒤쪽에 부호 문자가 올 수 있음

  * NumberFormatInfo.PositiveSign: 양수 기호

  * NumberFormatInfo.NegativeSign: 음수 기호

 

 - AllowParentheses: 숫자를 둘러싸는 괄호가 존재 할 수 있음

 

 - AllowThousands: 숫자에 단위 구분 기호가 존재 할 수 있음

  * NumberFormatInfo.CurrencyGroupSeparator: 통화 기호 포함시, 단위 구분자

  * NumberFormatInfo.CurrencyGroupSizes: 통화 기호 포함시, 단위 자릿수

  * NumberFormatInfo.NumberGroupSeparator: 일반, 단위 구분자

  * NumberFormatInfo.NumberGroupSizes: 일반, 단위 자릿수

  

 - AllowCurrencySymbol: 숫자에 통화 기호가 포함 될 수 있음

  * NumberFormatInfo.CurrencySymbol  

 

 - AllowDecimalPoint: 소수점이 포함 될 수 있음

  * NumberFormatInfo.CurrencyDecimalSeparator: 통화 기호 포함시, 소수 구분자

  * NumberFormatInfo.NumberDecimalSeparator: 일반, 소수 구분자

 

 - AllowExponent: 지수 표현식이 포함 될 수 있음 (nEx, nE+x, nE-x, nex, ne+x, ne-x)

 

 - AllowHexSpecifier: 숫자 문자열이 16진수 값을 나타냄

  * 대소문자 구별 없음

  * 0x, &h와 같은 접미사가 들어간 문자열은 인식하지 못함(예외 발생)

 

 

2. 합성 멤버

 - Integer: LS

 - Float: LS, DP, E

 - Number: LS, TS, DP, T

 - HexNumber: HS

 - Currency: LS, TS, P, DP, T, CS

 - Any: LS, TS, P, DP, T, E, CS

 

 

3. 자료형에 따른 기본 값

 - 정수형: LS

 - double, float: LS, DP, T, E

 - decimal: LS, TS, DP, T

 

 

 

:: 포맷팅 ::

날짜 및 시간 서식 문자열

- DateTime이나 DateTimeOffset을 위한 서식 문자열

 

1. 문화권 감지

 d : 짧은 날짜

 D : 긴 날짜

 t : 짧은 시간

 T : 긴 시간

 f : 긴 날짜 + 짧은 시간

 F : 긴 날짜 + 긴 시간

 g : 짧은 날짜 + 짧은 시간

 G : 짧은 날짜 + 긴 시간 (기본값)

 m, M : 월과 일

 y, Y : 연도와 월

 

반응형

2. 문화권 무시

 o : 복원 가능

  - DateTimeKind가 Unspecified가 아닌 한, 시간대 정보를 붙힘

 

 r, R : RFC 1123 표준, 

  - UTC를 고려한 시간대 접미사를 붙힘

  - 지역 시간을 UTC로 자동 변환하지 않기 때문에 DateTime.ToUniversalTime을 이용해서 명시적으로 UTC로 변환해줘야 한다.

 

 s : 정렬 가능 ISO 8601, 텍스트 기반 정렬 지원

 

 u : 정렬 가능 UTC, 텍스트 기반 정렬 지원

  - 지역 시간을 UTC로 자동 변환하지 않기 때문에 DateTime.ToUniversalTime을 이용해서 명시적으로 UTC로 변환해줘야 한다.

 

 U : UTC, UTC로 변환된 긴 날짜 + 짧은 시간

  - 지역 시간을 UTC로 자동 변환

 

3. 커스텀 수식 문자열

 g, gg : 캘린더에 따른 시대(era)명

 y: 년도 중 뒷 두자리만 표시

 yy : 년도 중 뒷 두자리만 표시 (0 채움)

 yyyy : 년도를 전체 표시

 M : 월

 MM : 월 (0 채움)

 MMM : 문화권에 따른 단축된 월명

 MMMM : 문화권에 따른 월명

 d : 일

 dd : 일 (0 채움)

 ddd : 문화권에 따른 단축된 요일명

 dddd : 문화권에 따른 요일명

 t : AM/PM (약자)

 tt : AM/PM

 h : 시간 (12시간제)

 hh : 시간 (0 채움, 12시간제)

 H : 시간 (24시간제)

 HH : 시간 (0 채움, 24시간제)

 m : 분

 mm : 분 (0 채움)

 s : 초

 ss : 초 (0 채움)

 : : 시간 구분자

 / : 날짜 구분자

 

:: 파싱 ::

DateTime의 파싱 및 파싱 오해

- 일이나 월이 연도보다 앞인 날짜 문자열은 중의적(월과 일을 서로 바꿔 인식할 수 있음)이기에 오해 발생

- 해결법

 * 서식화와 파싱을 수행 할 때 항상 동일한 문화권을 명시적으로 지정

 * DateTime과 DateTimeOffset을 문화권에 독립적인 방식으로 서식화

  ("o"같은 문화권과 별도로 표준화된 서식 문자열을 쓰면 더 좋다)

 

DateTimeStyles 열거형

(System.Globalization.Datetimestyles)

 

- 플래그 열거형(Flags 특성이 지정된 enum)

- DateTimeOffset에 Parse를 호출 할 때 서식에 대한 추가적인 지시사항을 제공

 

- None: 기본 값

AdjustToUniversal: Local 시간을 UTC 시간으로 변환. Local인지 UTC인지 알 수 없으면 변환하지 않고 Unspecified로.

- AllowInnerWhite: 패턴에 포함된 공백을 제외하고, 문자열 중간의 추가 공백 문자를 무시

- AllowLeadingWhite: 패턴에 포함된 공백을 제외하고, 문자열 처음의 공백 문자를 무시

AllowTrailingWhite: 패턴에 포함된 공백을 제외하고, 문자열 마지막의 공백 문자를 무시

AllowWhiteSpaces: 패턴에 포함된 공백을 제외하고, 모든 공백 문자를 무시 (AIW + ALW + ATW)

- AssumeLocal: 표준 시간대가 지정되지 않은 경우 Local 시간대인 것으로 가정

- AssumeUniversal: 표준 시간대가 지정되지 않은 경우 UTC인것으로 가정

- NoCurrentDateDefault: 시간만 있는 경우, 0001년 01월 01로 가정함

- RoundtripKind: "o", "r" 같이 시간대 정보(DateTimeKind)가 저장된 텍스트일 경우 그를 복원하기 위해 사용

                   (정확한 사용 용도를 모르겠음...)

 

:: 포맷팅 ::

열거형 서식 문자열

 G, g : 일반

 F, f: enum에 Flags 특성이 적용된 것 처럼 취급

 D, d: 십진수

 X, x: 십육진수

 

using System;
using System.Globalization;
using System.Text;
 
namespace Practice
{
    class Program
    {
        static void Main(string[] args)
        {
            int max = 17;          
 
            // 정수형에만 적용되는 표준 수치 서식 문자열
            char[] charForInt = "DXx".ToCharArray();
            int IntData = 129123456;
            foreach (char item in charForInt)
            {
                formatPrinter(IntData, item, max);
            }
 
            // 실수형에서도 적용 가능한 표준 수치 서식 문자열
            char[] charForDouble = "GgFNEeCP".ToCharArray();
            double doubleData = 1293.9150149231657317248;
            foreach (char item in charForDouble)
            {
                formatPrinter(doubleData, item, max);
            }
            formatPrinter(doubleData, 'R', -1);
 
 
            // 커스텀 수치 문자열
            double customData = 1230.456789;
 
            formatSimplePrinter(customData, ".##");             // 숫자 자리표
            formatSimplePrinter(customData, "000000.000000");   // 0자리표
            formatSimplePrinter(customData, "#,#");             // 그룹 구분자
            formatSimplePrinter(customData, "#,");              // 승수
            formatSimplePrinter(customData, "00%");             // 퍼센트
            formatSimplePrinter(customData, "000E+0");          // 지수 표기
            formatSimplePrinter(customData, "\\#.00");          // 리터럴 문자 인용        
            formatSimplePrinter(customData, "'...'.00");        // 리터럴 문자열 인용
 
            formatSimplePrinter(0, "0;(0);zero");               // 섹션 구분자
            formatSimplePrinter(-1, "0;(0);zero");              // 섹션 구분자
            formatSimplePrinter(1, "0;(0);zero");               // 섹션 구분자
 
           
            // NumberStyles 열거형
            // 일반 멤버
            Console.WriteLine(int.Parse("  45", NumberStyles.AllowLeadingWhite));
            Console.WriteLine(int.Parse("45  ", NumberStyles.AllowTrailingWhite));
            Console.WriteLine(int.Parse("-45", NumberStyles.AllowLeadingSign));
            Console.WriteLine(int.Parse("45-", NumberStyles.AllowTrailingSign));
            Console.WriteLine(int.Parse("(45)", NumberStyles.AllowParentheses));
            Console.WriteLine(int.Parse("45,000,000", NumberStyles.AllowThousands));
            Console.WriteLine(int.Parse("\\1000", NumberStyles.AllowCurrencySymbol));
            Console.WriteLine(double.Parse("45.101", NumberStyles.AllowDecimalPoint));
            Console.WriteLine(decimal.Parse("3e+6", NumberStyles.AllowExponent));
            Console.WriteLine(int.Parse("3aC", NumberStyles.AllowHexSpecifier));
            Console.WriteLine();
 
            // 합성 멤버
            Console.WriteLine(int.Parse("  2", NumberStyles.Integer));
            Console.WriteLine(double.Parse("22.44", NumberStyles.Float));
            Console.WriteLine(int.Parse("1,000,000", NumberStyles.Number));
            Console.WriteLine(int.Parse("4ac", NumberStyles.HexNumber));
            Console.WriteLine(double.Parse("\\(5.20)", NumberStyles.Currency));
            Console.WriteLine(decimal.Parse("3e6", NumberStyles.Any));
            Console.WriteLine();
 
            // 자료형에 따른 기본 값
            Console.WriteLine(int.Parse("  2"));
            Console.WriteLine(double.Parse("1,222.44"));
            Console.WriteLine(decimal.Parse("3-"));
            Console.WriteLine();
 
            // 커스텀
            NumberFormatInfo ni = new NumberFormatInfo();
            ni.CurrencySymbol = "$";
            ni.CurrencyGroupSeparator = " ";
            double million = double.Parse("$1 000 000", NumberStyles.Currency, ni);
            Console.WriteLine();
 
 
            // 날짜-시간 서식 문자열
            // DateTime, DateTime 열거형
 
            DateTime DTNow = DateTime.Now;
 
            // 문화권 감지
            char[] charForDateTimeLocal = "dDtTfFgGmMyY".ToCharArray();
            foreach (var item in charForDateTimeLocal)
            {
                formatSimplePrinter(DTNow, item);
            }
            Console.WriteLine();
 
            // 문화권 무시
            char[] charForDateTimeInvariant = "orRsuU".ToCharArray();
            foreach (var item in charForDateTimeInvariant)
            {
                formatSimplePrinter(DTNow, item);
            }
            Console.WriteLine();
 
            // 커스텀
            formatSimplePrinter(DTNow, "g y/M/d(ddd) tt h:m:s");
 
            formatSimplePrinter(DTNow, "gg");
 
            formatSimplePrinter(DTNow, "yyyy");
            formatSimplePrinter(DTNow, "yy");
 
            formatSimplePrinter(DTNow, "MMMM");
            formatSimplePrinter(DTNow, "MMM");
            formatSimplePrinter(DTNow, "MM");
 
            formatSimplePrinter(DTNow, "dddd");
            formatSimplePrinter(DTNow, "ddd");
            formatSimplePrinter(DTNow, "dd");
 
            formatSimplePrinter(DTNow, "tt");
 
            formatSimplePrinter(DTNow, "hh");
            formatSimplePrinter(DTNow, "HH");
            formatSimplePrinter(DTNow, "mm");
            formatSimplePrinter(DTNow, "ss");
 
 
 
            //DateTime의 파싱 및 파싱 오해
            //"o" 서식을 이용한 파싱
            string s = DateTime.Now.ToString("o");
 
            // 가능하다면 ParseExact를 쓰는것이 낫다.
            // 잘못 파싱되는 쪽 보다 예외를 뿜어내는 쪽이 더 나은 편.
            DateTime DT1 = DateTime.ParseExact(s, "o", null);
            DateTime DT2 = DateTime.Parse(s);
 
 
            // DateTimeStyles 열거형
            CultureInfo IC = CultureInfo.InvariantCulture;
 
            Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.None));          
            Console.WriteLine(DateTime.Parse("01:12:23 +09:00", IC, DateTimeStyles.AdjustToUniversal));          
            Console.WriteLine(DateTime.Parse("  01 : 12 : 23  ", IC, DateTimeStyles.AllowWhiteSpaces));
            Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.AssumeLocal));
            Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.AssumeUniversal));
            Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.NoCurrentDateDefault));
            Console.WriteLine(DateTime.Parse(s, IC, DateTimeStyles.RoundtripKind));
 
 
            // 열거형 서식 문자열
            string[] stringForEnum = "G g F f D d X x".Split();
            foreach (var item in stringForEnum)
            {              
                Console.WriteLine(DateTimeStyles.AllowWhiteSpaces.ToString(item));
            }
        }
 
        static void formatPrinter(dynamic data, char formatChar, int max)
        {
            int index = 0;
            StringBuilder sb = new StringBuilder();
            string[] formatString = new string[max + 2];
 
            for (int i = 0; i < formatString.Length; i++)
            {
                sb.Clear();
                sb.Append("{");
                sb.Append(index);
                sb.Append(":");
                sb.Append(formatChar);
                if (i != 0)
                {
                    sb.Append(i - 1);
                }
                sb.Append("}");
                formatString[i] = sb.ToString();
 
                Console.Write((formatString[i] + ": ").PadLeft(20));
                Console.WriteLine(formatString[i], data);
            }
            Console.WriteLine();
        }
 
        static void formatSimplePrinter(dynamic data, string format)
        {
            int index = 0;
            string formatString;
           
            StringBuilder sb = new StringBuilder();          
            sb.Append("{");
            sb.Append(index);
            sb.Append(":");
            sb.Append(format);
            sb.Append("}");
            formatString = sb.ToString();
 
            Console.Write((formatString + ": ").PadLeft(20));
            Console.WriteLine(formatString, data);
        }
 
        static void formatSimplePrinter(dynamic data, char format)
        {
            formatSimplePrinter(data, format.ToString());
        }
    }
}

 

 

 

반응형

'C#' 카테고리의 다른 글

[C#] BitConverter  (1) 2023.08.17
[C#] XmlConvert  (1) 2023.08.16
[C#] Convert  (2) 2023.08.15
[C#] 서식화(Formatting)와 파싱(Parsing)  (1) 2023.08.14
[C#] Time​Zone​Info.​Adjustment​Rule & Time​Zone​Info.​Transition​Time  (1) 2023.08.12
[C#] TimeZoneInfo  (1) 2023.08.11
[C#] TimeZone  (1) 2023.08.10
[C#] DateTime & DateTimeOffset  (0) 2023.07.06