서식화(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#] TimeZoneInfo.AdjustmentRule & TimeZoneInfo.TransitionTime (1) | 2023.08.12 |
[C#] TimeZoneInfo (1) | 2023.08.11 |
[C#] TimeZone (1) | 2023.08.10 |