본문 바로가기
C#

[C#] 서식화(Formatting)와 파싱(Parsing)

by DANEW 2023. 8. 14.

서식화(Formatting) : 뭔가를 문자열로 변경

파싱(Parsing) : 문자열을 뭔가로 변경

 

1. ToString / Parse

- ToString: 단순 값 형식에 대해 이해할만 한 결과를 돌려줌.

- Parse: ToString의 반대 방향 변환

 * Parse가 실패하면 FormatException 예외 발생

 * TryParse를 사용하면 실패시 false를 반환해 줌

 

- DateTime, DateTimeOffset, 수치 형식들에 대한 Parse, TryParse는 지역 문화권 설정을 존중함.

- 이외의 문화권은 CultureInfo 객체를 직접 지정. 불변 문화권(InvariantCulture)가 바람직한 경우가 많음.

 

2. 서식 공급자(format provider)

- 서식자와 파싱이 작동하는 방식을 좀 더 세밀하게 세어.

 

- IFormattable 인터페이스 (System.IFormattable)

 * string ToString (string format, IFormatProvider formatProvider);

  + string format - 서식 문자열: 서식화를 위한 명령들을 제공

  + IFormatProvider formatProvider - 서식 공급자: 명령들을 해석하는 방식을 결정

 * null을 인자로 주면, 기본 서식 문자열 또는 기본 서식 공급자가 선택됨.

 * 편의를 위해 공급자를 생략한 버전(공급자가 null)도 제공함.

 

CultureInfo 클래스 (System.Globalization.CultureInfo)

 * 다른 두 서식 공급자에 대한 간접 메커니즘으로 작동함

 * 현재 문화권의 지역 설정에 적용 가능한 NumberFormatInfo나 DateTimeFormatInfo 객체를 돌려 줌

 

NumberFormatInfo 클래스 (System.Globalization.NumberFormatInfo)

DateTimeFormatInfo 클래스 (System.Globalization.DateTimeFormatInfo)

 * CultureInfo를 통하지 않은 직접 생성은 기본적으로 불변 문화권 설정을 기본으로 함

 * Clone을 통해 공급자 복사 가능, 이 경우 읽기 전용 풀림

 

- 복합 서식화(Composite Format String)

 * 서식 문자열에 변수 대입(variable substitution)을 결합

 

- 서식 공급자를 이용한 파싱

 * 표준적인 인터페이스는 없음

  1) 파싱 시 서식 공급자를 인수를 받는 (Try)Parse 제공

  2) NumberStyles나 DateTimeStyles 열거형 받는 버전 제공

 

반응형

- IFormatProvider 인터페이스 (System.IFormatProvider)

 * 모든 서식 공급자가 구현하는 인터페이스

 * 간접층을 제공, 더 적절한 서식 공급자를 선택 할 수 있게 해줌 (CultureInfo처럼)

 * object GetFormat (Type formatType);

 

- ICustomFormatter 인터페이스 (System.ICustomFormatter)

 * 커스텀 서식 공급자를 작성하기 위해 구현하는 인터페이스

 * string Format(string format, object arg, IFormatProvider formatProvider)

 

 
using System;
using System.Threading;
using System.Globalization;
using System.Text;

namespace Practice
{
    class Program
    {
        static void Main(string[] args)
        {
            // ToString, Parse

            string s = true.ToString();     // s = "True"
            bool b = bool.Parse(s);         // b = true

            // Parse가 실패하면 FormatException 예외 발생
            try
            {
                s = "ture";
                b = bool.Parse(s);
            }
            catch (FormatException e)
            {
                Console.WriteLine($"{e}\n");                
            }

            // TryParse가 실패하면 false를 돌려줌
            bool.TryParse(s, out b);
            Console.WriteLine($"{b}\n");


            // 문화권 지정

            // 현재 문화권 저장
            CultureInfo CIbefore = CultureInfo.CurrentCulture;
           
            // 독일 문화권 (de-DE)
            CultureInfo CIafter = new CultureInfo("de-DE");

            // 현 스래드의 문화권을 독일 문화권으로 변경
            Thread.CurrentThread.CurrentCulture = CIafter;

            // 독일에서는 1.234가 아니라 1234로 파싱함
            Console.WriteLine(double.Parse("1.234"));

            // 불변 문화권을 이용하여 포맷팅 / 파싱
            Console.WriteLine(double.Parse("1.234", CultureInfo.InvariantCulture));
            string x = 1.234.ToString(CultureInfo.InvariantCulture);

            // 문화권을 원래대로            
            Thread.CurrentThread.CurrentCulture = CIbefore;


            // 서식 공급자
            // IFormattable 인터페이스를 구현
            // NumberFormatInfo, DataTimeFormatInfo, CultureInfo

            // 화폐 단위 변경
            NumberFormatInfo f = new NumberFormatInfo();
            f.CurrencySymbol = "$$";
            Console.WriteLine(3.ToString("C", f));
            Console.WriteLine();

            // 기본 서식 문자열, 공급자 적용(CultureInfo.CurrentCulture)
            Console.WriteLine(10.3.ToString("C", null));    // 화폐, 공급자 생략
            Console.WriteLine(10.3.ToString("C"));          // 화폐, 공급자 생략
            Console.WriteLine(10.3.ToString("F4"));         // 소수 네 자리수, 공급자 생략
            Console.WriteLine();


            // 서식 공급자와 CultureInfo
            CultureInfo CIuk = CultureInfo.GetCultureInfo("en-GB");
            Console.WriteLine(3.ToString("C", CIuk));       // 화폐, 영국 문화권
            Console.WriteLine();

            DateTime DTNow = DateTime.Now;
            CultureInfo CIiv = CultureInfo.InvariantCulture;
            Console.WriteLine(DTNow.ToString(CIiv));        // 기본 서식, 불변 문화권
            Console.WriteLine(DTNow.ToString("d", CIiv));   // 짧은 날짜, 불변 문화권
            Console.WriteLine();


            // NumberFormatInfo 또는 DateTimeFormatInfo의 활용
            // 초기 생성시 불변 문화권 설정을 따름

            // 숫자 구분자 변경
            NumberFormatInfo NfiCustom = new NumberFormatInfo();
            NfiCustom.NumberGroupSeparator = " ";
            Console.WriteLine(12345.6789.ToString("N3", NfiCustom));
            Console.WriteLine();

            // 다른 문화권에서 설정 복사, 원래의 공급자가 읽기 전용이더라도 새로운 공급자는 쓰기 가능
            NumberFormatInfo NfiCloned = (NumberFormatInfo)CultureInfo.CurrentCulture.NumberFormat.Clone();


            // 복합 서식화(composite format string)
            // 서식 문자열에 변수 대입(variable substitution)을 결합

            // 1.
            string composite = "Credit={0:C}";
            Console.WriteLine(string.Format(composite, 500));

            // 2. 1의 축약            
            Console.WriteLine("Credit={0:C}", 500);
            Console.WriteLine();


            // 서식 공급자를 이용한 파싱
            // NumberStyles, DateTimeStyles
            // 기본적으로는 괄호, 화폐 기호 등의 입력 문자열을 허용하지 않음.

            // 서식 공급자 미사용
            try
            {
                Console.WriteLine(int.Parse("(2)"));
            }
            catch (FormatException e)
            {
                Console.WriteLine(e);
                Console.WriteLine();
            }
           
            // 서식 공급자 사용
            Console.WriteLine(int.Parse("(2)", NumberStyles.Integer | NumberStyles.AllowParentheses));
            Console.WriteLine(decimal.Parse("$5.20", NumberStyles.Currency, CultureInfo.GetCultureInfo("us-US")));
            Console.WriteLine();


            // IFormatProvide, ICustomFormatter
            IFormatProvider FP = new WordyFormatProvider();
            Console.WriteLine(string.Format(FP, "{0}의 영어 표현은 {0:W}", -123.45));
            Console.WriteLine();            
        }

        public class WordyFormatProvider : IFormatProvider, ICustomFormatter
        {
            static readonly string[] _numberWords = "공 하나 둘 삼 넷 오 여섯 칠 팔 아홉 마이너스 점".Split();

            // 소비자가 서식 공급자들을 연달아 적용 할 수 있게 한다.
            // 부모 서식 공급자를 설정
            IFormatProvider _parent;

            // 직접 부모 문화권을 선택 할 수 있음
            public WordyFormatProvider(IFormatProvider parent)
            {
                _parent = parent;
            }

            // 기본값은 현재 사용중인 문화권
            public WordyFormatProvider() : this (CultureInfo.CurrentCulture) { }

            // GetFormat 메서드는 더 구체적인 객체로 작업을 위임하는 역할을 함
            object IFormatProvider.GetFormat(Type formatType)
            {
                if (formatType == typeof(ICustomFormatter))
                {
                    return this;
                }
                else
                {
                    return null;
                }                
            }

            string ICustomFormatter.Format(string format, object arg, IFormatProvider prov)
            {
                // 이 공급자가 지원하는 서식 문자열이 아니면 부모 공급자에게 위임한다.
                if (arg == null || format != "W")
                {
                    return string.Format(_parent, "{0:" + format + "}", arg);
                }

                StringBuilder result = new StringBuilder();
                string digitList = string.Format(CultureInfo.InvariantCulture, "{0}", arg);

                foreach (char digit in digitList)
                {
                    // 해당 스트링에서 들어온 글자를 검색
                    int i = "0123456789-.".IndexOf(digit);

                    // 존재하지 않으면 스킵
                    if (i == -1)
                    {
                        continue;
                    }

                    // 첫 기록이 아닌 경우 공백 추가
                    if (result.Length > 0)
                    {
                        result.Append(' ');
                    }

                    result.Append(_numberWords[i]);
                }
                return result.ToString();                
            }
        }
    }    
}

 

 

 

반응형

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

[C#] BigInteger  (1) 2023.08.18
[C#] BitConverter  (1) 2023.08.17
[C#] XmlConvert  (1) 2023.08.16
[C#] Convert  (2) 2023.08.15
[C#] 표준 서식 문자열과 파싱 플래그  (1) 2023.08.13
[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