C#/.NET에서 문자열을 서식 지정하는 방법은 다양해요. 객체를 단순히 이어 붙이는 방법부터 재정의된 object.ToString() 메서드 호출, ICustomFormatter 사용(이 연습 문제에서는 다루지 않아요)에 이르기까지 여러 가지가 있어요.
문자열 서식 지정에서 가장 흔히 쓰이는 두 가지 방법은 문자열 보간과 String.Format()이에요. StringBuilder (cross-ref-tba) 클래스도 여러 줄처럼 복잡한 경우에 문자열을 만들어 나가는 데 사용할 수 있어요.
ToString() 사용하기모든 클래스와 구조체가 상속받는 System.Object()에는 ToString() 메서드가 있어요. 예를 들어 new DateTime(2019, 5, 23).ToString()은 "05/23/2019 00:00:00"을 출력해요(미국 문화권의 스레드에서요. 아래를 참고해요). 문자열 연결처럼 이 기본 ToString() 메서드가 암시적으로 호출되는 상황도 있어요. "" + new DateTime(2019, 5, 23)도 같은 결과를 내요.
기본 ToString() 메서드 외에도, 서식 지정이 문제가 되는 타입에는 서식 문자열이나 서식 제공자를 받는 오버로드가 있어요. 특히 BCL(Base Class Library)에서는 숫자, 날짜, 열거형, GUID가 그래요.
String.Format()은 고정된 텍스트와 자리 표시자, 그리고 개수가 정해지지 않은 인자들을 받아요. 이때 문자열은 문서에서 _복합 서식_이라고 하고, 자리 표시자는 _서식 항목_이라고 해요. 반환 값은 각 _서식 항목_을 대응하는 인자로 해석한 뒤, 해석된 값들을 고정된 텍스트와 합쳐요.
string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25))
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
서식을 일종의 템플릿처럼 여러 식에서 사용하거나, [축자 문자열][verbatim-strings]을 쓸 때처럼 서식과 서식 지정할 식을 함께 넣기가 너무 번거로울 때는 보간보다 Format()이 더 나은 선택일 수 있어요.
이 방법을 기술적으로는 복합 서식 지정이라고 해요.
_복합 서식 지정_을 활용하는 문자열 생성 메서드의 더 자세한 목록은 이 문서에 있어요.
보간 문자열은 앞에 $를 붙이고, 중괄호로 감싼 런타임 식을 포함해요. 서식 항목의 구문은 다음과 같아요: $"{<interpolationExpression>[,<alignment>][:<formatString>]}". 보간 문자열을 쓰면 별도의 인자 목록이 필요 없어요. 결과는 기능적으로 String.Format() 방식과 동일해요.
식에는 스코프 안에 있는 무엇이든 들어갈 수 있어요. _맞춤_은 텍스트가 들어가는 "필드"의 길이예요. _맞춤_이 양수이면 텍스트 왼쪽에 공백을 채우고, 음수이면 텍스트 오른쪽에 채워요.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
중괄호 안의 텍스트, 즉 복합 서식에서는 자리 표시자, 문자열 보간에서는 보간 식을 _서식 항목_이라고 해요.
서식 항목은 최대 세 부분으로 이루어질 수 있어요. 첫 번째는 위 예제 코드에서 본 것처럼 반드시 필요한 식 또는 인자 자리 표시자예요. 여기에 더해 선택적인 맞춤(쉼표 ","로 시작해요)과 선택적인 서식 문자열(콜론 ":"으로 시작해요)이 있어요.
{<interpolationExpression>[,<alignment>][:<formatString>]}
_맞춤_은 텍스트가 놓이는 "필드"의 길이를 지정하는데, 맞춤이 양수이면 왼쪽에 공백을 채우고 음수이면 오른쪽에 채워요.
_서식 문자열_은 텍스트 출력의 모양, 예를 들어 숫자에 천 단위 구분 기호를 넣을지, DateTime 객체의 날짜 부분만 출력할지 등을 지정해요.
다음 코드는 DateTime 객체의 날짜 부분과 실수를 지수 형식으로 표시하는 방법을 보여줘요.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password."
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
string.Format(
"I had {0:E} bitcoins on {1:d}, the day I forgot my password.",
loadsOf, thatDay)
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
숫자와 날짜 모두에 대해 표준 서식과 사용자 지정 서식이 있어요. _사용자 지정_과 표준 사이에 결정적인 차이는 없어요. 다만 서식 문자로 사용자 지정 서식 문자열을 직접 조합할 수 있다는 점이 달라요. 이 맥락에서 "custom"은 나만의 사용자 지정 서식기를 만들 때 사용하는 ICustomFormatter 인터페이스와는 아무 관련이 없어요.
BCL(Base Class Library)은 DateTimeFormatInfo와 NumberFormatInfo, 두 가지 서식기를 제공하고, 서식 문자열을 여섯 그룹으로 제공해요.
다양한 서식 문자열 목록은 다음과 같아요:
Enum과 GUID _서식 문자열_은 _표준_으로 분류할 수 있어요. enum과 GUID에는 IFormatProvider를 받는 ToString() 오버로드가 있긴 하지만, 그것이 실제로 하는 일이 있는지는 분명하지 않아요.
라이브러리에서는 (_서식 문자열_이 그저 문자열로 표현된다는 점을 넘어서) _서식 문자열_에 어느 정도 일관성을 부여하려고 해요. 이런 일관성에 대한 노력은 표준 문자열에서 볼 수 있어요. 실제로 개발자라면 표준 문자열과 사용자 지정 문자열의 차이에 신경 쓸 일은 거의 없어요. 직접 만든 클래스에 서식기를 구현하는 경우, 클래스에 그럴 필요가 있어 보인다면 기존 표준 문자열을 그대로 따르는 것이 좋아요. 하지만 그 차이는 사실상 무시해도 괜찮아요.
실행 스레드마다 기본 문화권 Thread.CurrentThread.CurrentCulture가 있고, 이는 CultureInfo 인스턴스에 담겨 있어요. 스레드의 문화권은 영국식 _DD/MM/YYYY_와 미국식 _MM/DD/YYYY_처럼 지역별 차이를 반영해 날짜와 숫자가 기본적으로 어떻게 서식 지정되는지를 결정해요.
CultureInfo는 IFormatProvider 인터페이스를 구현하고 있어서, String.Format()의 특정 오버로드에 전달할 수 있어요. 이는 스레드 문화권을 재정의하는 데 사용할 수 있어요.