C# 문자열 다루기: 기본 조작과 포맷팅 🎨✨
안녕, 친구들! 오늘은 C#에서 문자열을 다루는 방법에 대해 재미있게 알아볼 거야. 😊 문자열은 프로그래밍에서 정말 중요한 녀석이지? 우리가 매일 사용하는 텍스트를 프로그램에서 어떻게 다루는지 알면, 정말 멋진 애플리케이션을 만들 수 있어!
그럼 이제부터 C# 문자열의 세계로 빠져볼까? 🏊♂️ 준비됐니?
참고: 이 글은 재능넷(https://www.jaenung.net)의 '지식인의 숲' 메뉴에 등록될 예정이야. 재능넷은 다양한 재능을 거래하는 플랫폼이니, 프로그래밍 실력을 키워서 거기서 네 재능을 뽐내보는 것도 좋겠어!
1. 문자열의 기본 🍎
자, 먼저 문자열이 뭔지 알아볼까? C#에서 문자열은 string
타입으로 표현돼. 문자열은 쉽게 말해서 텍스트야. 예를 들면 이렇게:
string greeting = "안녕하세요, C# 세상!";
Console.WriteLine(greeting);
이렇게 하면 콘솔에 "안녕하세요, C# 세상!"이 출력될 거야. 쉽지? 😄
문자열 연결하기 🔗
문자열을 이어붙이고 싶을 때는 +
연산자를 사용해. 예를 들어:
string firstName = "길동";
string lastName = "홍";
string fullName = lastName + firstName;
Console.WriteLine(fullName); // 출력: 홍길동
와! 이렇게 간단하게 이름을 만들 수 있어. 재능넷에서 프로필을 만들 때 이런 기능을 쓸 수 있겠지?
문자열 길이 알아내기 📏
문자열의 길이를 알고 싶을 때는 Length
속성을 사용해:
string message = "C#은 정말 재미있어!";
int length = message.Length;
Console.WriteLine($"메시지의 길이: {length}"); // 출력: 메시지의 길이: 13
여기서 $
와 {}
를 사용한 건 문자열 보간이라고 해. 나중에 더 자세히 알아볼 거야!
2. 문자열 조작하기 🛠️
이제 문자열을 더 재미있게 다뤄볼까? C#은 문자열을 다루는 다양한 메서드를 제공해. 하나씩 살펴보자!
대소문자 변경 🔠🔡
문자열을 모두 대문자나 소문자로 바꾸고 싶을 때는 이렇게 해:
string original = "Hello, World!";
string upper = original.ToUpper();
string lower = original.ToLower();
Console.WriteLine(upper); // 출력: HELLO, WORLD!
Console.WriteLine(lower); // 출력: hello, world!
이런 기능은 사용자 입력을 처리할 때 정말 유용해. 예를 들어, 재능넷에서 검색 기능을 만들 때 대소문자 구분 없이 검색할 수 있게 해주는 거지.
문자열 자르기 ✂️
문자열의 일부분만 필요할 때는 Substring
메서드를 사용해:
string sentence = "C#으로 코딩하는 건 정말 재미있어!";
string part = sentence.Substring(0, 7);
Console.WriteLine(part); // 출력: C#으로 코딩
여기서 0은 시작 인덱스, 7은 가져올 문자 수를 의미해. C#에서는 인덱스가 0부터 시작한다는 걸 기억해!
문자열 찾기 🔍
특정 문자나 문자열이 어디에 있는지 찾고 싶을 때는 IndexOf
메서드를 사용해:
string text = "C#은 마이크로소프트가 만든 프로그래밍 언어야.";
int index = text.IndexOf("마이크로소프트");
Console.WriteLine($"'마이크로소프트'의 위치: {index}"); // 출력: '마이크로소프트'의 위치: 5
이 기능을 사용하면 긴 문자열에서 특정 단어를 찾아내는 게 쉬워져. 재능넷에서 게시글 내용을 검색할 때 이런 기능을 쓸 수 있겠지?
문자열 바꾸기 🔄
문자열의 일부를 다른 것으로 바꾸고 싶을 때는 Replace
메서드를 사용해:
string original = "나는 파이썬을 좋아해.";
string replaced = original.Replace("파이썬", "C#");
Console.WriteLine(replaced); // 출력: 나는 C#을 좋아해.
이렇게 하면 텍스트를 쉽게 수정할 수 있어. 예를 들어, 재능넷에서 사용자가 입력한 텍스트에서 부적절한 단어를 자동으로 필터링하는 기능을 만들 수 있겠지?
3. 문자열 포맷팅 🎨
이제 문자열을 더 예쁘게 꾸미는 방법을 알아볼까? C#에서는 문자열을 포맷팅하는 여러 가지 방법이 있어.
문자열 보간 (String Interpolation) 🧙♂️
앞서 잠깐 언급했던 문자열 보간에 대해 더 자세히 알아보자. 이 방법을 사용하면 문자열 안에 변수나 표현식을 쉽게 넣을 수 있어:
string name = "철수";
int age = 25;
string message = $"{name}는 {age}살이에요.";
Console.WriteLine(message); // 출력: 철수는 25살이에요.
문자열 앞에 $
를 붙이고, 변수나 표현식을 {}
안에 넣으면 돼. 정말 편리하지?
복합 형식 지정 (Composite Formatting) 🎭
복합 형식 지정은 문자열 보간보다 조금 더 복잡하지만, 더 세밀한 제어가 가능해:
string name = "영희";
double height = 165.5;
Console.WriteLine("이름: {0}, 키: {1:F1}cm", name, height);
// 출력: 이름: 영희, 키: 165.5cm
여기서 {0}
, {1}
은 순서대로 뒤에 오는 인자를 나타내. F1
은 소수점 한 자리까지 표시하라는 의미야.
문자열 형식 지정 (String.Format) 🖌️
String.Format
메서드를 사용하면 복합 형식 지정을 더 유연하게 사용할 수 있어:
string name = "민수";
int score = 95;
string result = String.Format("{0}의 점수는 {1}점입니다.", name, score);
Console.WriteLine(result); // 출력: 민수의 점수는 95점입니다.
이 방법은 특히 여러 곳에서 같은 형식의 문자열을 사용할 때 유용해. 재능넷에서 사용자 프로필을 표시할 때 이런 방식을 쓸 수 있겠지?
숫자 형식 지정 🔢
숫자를 문자열로 표현할 때 다양한 형식을 사용할 수 있어:
double price = 1234.56;
Console.WriteLine($"가격: {price:C}"); // 출력: 가격: ₩1,234.56 (시스템 설정에 따라 다를 수 있음)
Console.WriteLine($"백분율: {0.75:P}"); // 출력: 백분율: 75.00%
Console.WriteLine($"16진수: {255:X}"); // 출력: 16진수: FF
C
는 통화, P
는 백분율, X
는 16진수를 나타내. 이런 형식들을 사용하면 숫자를 더 읽기 쉽게 표현할 수 있어.
4. 고급 문자열 기능 🚀
이제 좀 더 복잡한 문자열 작업에 대해 알아볼까? C#은 정말 강력한 문자열 처리 기능을 제공해. 함께 살펴보자!
정규 표현식 (Regular Expressions) 🕵️♂️
정규 표현식은 문자열 패턴을 검색하고 조작하는 강력한 도구야. C#에서는 System.Text.RegularExpressions
네임스페이스를 사용해 정규 표현식을 다룰 수 있어:
using System.Text.RegularExpressions;
string text = "내 이메일은 example@email.com이야.";
string pattern = @"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b";
Match match = Regex.Match(text, pattern);
if (match.Success)
{
Console.WriteLine($"찾은 이메일: {match.Value}");
}
// 출력: 찾은 이메일: example@email.com
이 예제는 문자열에서 이메일 주소를 찾는 거야. 정규 표현식을 사용하면 복잡한 패턴도 쉽게 찾을 수 있어. 재능넷에서 사용자 입력을 검증할 때 이런 기능을 사용할 수 있겠지?
StringBuilder 클래스 🏗️
많은 문자열 조작을 할 때는 StringBuilder
클래스를 사용하는 게 좋아. 이 클래스는 문자열을 효율적으로 수정할 수 있게 해줘:
using System.Text;
StringBuilder sb = new StringBuilder();
sb.Append("안녕하세요, ");
sb.Append("C#");
sb.Append("을 배우고 있어요!");
sb.Insert(7, "멋진 ");
string result = sb.ToString();
Console.WriteLine(result);
// 출력: 안녕하세요, 멋진 C#을 배우고 있어요!
StringBuilder
를 사용하면 문자열을 계속 수정해도 메모리를 효율적으로 사용할 수 있어. 긴 문자열을 만들 때 특히 유용하지.
문자열 분할과 결합 🧩
문자열을 여러 부분으로 나누거나 여러 문자열을 하나로 합칠 때 유용한 메서드들이 있어:
string sentence = "C#,Java,Python,JavaScript";
string[] languages = sentence.Split(',');
foreach (string lang in languages)
{
Console.WriteLine(lang);
}
// 출력:
// C#
// Java
// Python
// JavaScript
string joined = string.Join(" - ", languages);
Console.WriteLine(joined);
// 출력: C# - Java - Python - JavaScript
Split
메서드는 문자열을 특정 구분자를 기준으로 나누고, Join
메서드는 여러 문자열을 하나로 합쳐. 이런 기능들은 데이터를 처리할 때 정말 유용해.
문자열 비교 🔍
문자열을 비교할 때는 단순히 ==
연산자를 사용하는 것보다 더 세밀한 방법들이 있어:
string str1 = "hello";
string str2 = "HELLO";
bool areEqual = string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"대소문자 무시하고 비교: {areEqual}"); // 출력: 대소문자 무시하고 비교: True
int compareResult = string.Compare(str1, str2, StringComparison.Ordinal);
Console.WriteLine($"비교 결과: {compareResult}"); // 출력: 비교 결과: 32
StringComparison.OrdinalIgnoreCase
를 사용하면 대소문자를 무시하고 비교할 수 있어. Compare
메서드는 두 문자열의 순서를 비교해줘.
5. 문자열과 성능 🏎️
문자열을 다룰 때는 성능도 중요해. 특히 대량의 데이터를 처리할 때는 더욱 그렇지. 몇 가지 성능 관련 팁을 알아볼까?
문자열 불변성 이해하기 🧊
C#에서 문자열은 불변(immutable)이야. 이게 무슨 뜻이냐면, 한번 생성된 문자열은 변경할 수 없다는 거야. 예를 들어:
string str = "Hello";
str += " World";
이 코드는 새로운 문자열을 만들어내. 원래의 "Hello"는 그대로 있고, "Hello World"라는 새로운 문자열이 생성되는 거지. 이런 특성 때문에 문자열을 자주 수정하면 성능이 떨어질 수 있어.
StringBuilder 활용하기 🛠️
앞서 소개한 StringBuilder
를 사용하면 이런 성능 문제를 해결할 수 있어. 특히 반복문 안에서 문자열을 계속 수정할 때 유용해:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append($"숫자: {i}, ");
}
string result = sb.ToString();
이렇게 하면 문자열을 1000번 수정해도 새로운 문자열 객체를 계속 만들지 않아도 돼. 메모리 사용량도 줄이고 성능도 향상시킬 수 있지.
문자열 풀(String Pool) 이해하기 🏊♂️
C#은 문자열 풀이라는 특별한 메모리 영역을 사용해. 동일한 문자열 리터럴은 메모리에 한 번만 저장되고 재사용돼:
string str1 = "Hello";
string str2 = "Hello";
Console.WriteLine(object.ReferenceEquals(str1, str2)); // 출력: True
이 예제에서 str1
과 str2
는 실제로 같은 메모리 위치를 가리키고 있어. 이렇게 하면 메모리를 절약할 수 있지.
문자열 인터닝(String Interning) 🎭
문자열 인터닝은 동일한 내용의 문자열을 하나의 인스턴스로 관리하는 기술이야. C#에서는 string.Intern
메서드를 사용해 명시적으로 인터닝을 할 수 있어:
string str1 = "Hello, World!";
string str2 = new string(new char[] { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' });
Console.WriteLine(object.ReferenceEquals(str1, str2)); // 출력: False
str2 = string.Intern(str2);
Console.WriteLine(object.ReferenceEquals(str1, str2)); // 출력: True
인터닝을 사용하면 동일한 내용의 문자열을 여러 번 저장하지 않아도 돼서 메모리를 절약할 수 있어. 하지만 인터닝 과정 자체도 비용이 들기 때문에, 필요한 경우에만 사용하는 게 좋아.
6. 문자열과 국제화 🌍
프로그램을 여러 나라에서 사용할 수 있게 만들고 싶다면, 문자열을 다룰 때 국제화(Internationalization, i18n)를 고려해야 해. C#은 이를 위한 다양한 기능을 제공하지.
문화권 설정하기 🏳️
C#에서는 CultureInfo
클래스를 사용해 특정 문화권에 맞는 형식을 적용할 수 있어:
using System.Globalization;
double number = 1234567.89;
CultureInfo usCulture = new CultureInfo("en-US");
CultureInfo krCulture = new CultureInfo("ko-KR");
Console.WriteLine(number.ToString("C", usCulture)); // 출력: $1,234,567.89
Console.WriteLine(number.ToString("C", krCulture)); // 출력: ₩1,234,568
이렇게 하면 같은 숫자도 다른 국가의 형식에 맞게 표시할 수 있어. 재능넷같은 글로벌 플랫폼을 만든다면 이런 기능이 정말 유용할 거야!
날짜와 시간 형식 📅
날짜와 시간도 국가마다 표시 방식이 달라. C#에서는 이것도 쉽게 처리할 수 있어:
DateTime now = DateTime.Now;
CultureInfo frCulture = new CultureInfo("fr-FR");
CultureInfo jpCulture = new CultureInfo("ja-JP");
Console.WriteLine(now.ToString("D", frCulture)); // 예: mardi 15 juin 2023
Console.WriteLine(now.ToString("D", jpCulture)); // 예: 2023年6月15日
이렇게 하면 같은 날짜도 프랑스어와 일본어로 각각 다르게 표시할 수 있어.
리소스 파일 사용하기 📚
여러 언어를 지원하는 애플리케이션을 만들 때는 리소스 파일을 사용하는 게 좋아. 각 언어별로 별도의 리소스 파일을 만들고, 필요할 때 적절한 언어의 문자열을 불러오는 거지:
using System.Resources;
ResourceManager rm = new ResourceManager("YourNamespace.Strings", typeof(YourClass).Assembly);
CultureInfo culture = new CultureInfo("fr-FR");
string greeting = rm.GetString("HelloWorld", culture);
Console.WriteLine(greeting); // 출력: Bonjour le monde!
이렇게 하면 프로그램의 언어를 쉽게 전환할 수 있어. 재능넷 같은 플랫폼에서 다국어 지원을 할 때 이런 방식을 사용할 수 있겠지?
7. 문자열 보안 🔒
프로그래밍에서 보안은 정말 중요해. 특히 문자열을 다룰 때는 더욱 주의해야 해. 몇 가지 보안 관련 팁을 알아볼까?
사용자 입력 검증하기 ✅
사용자로부터 입력을 받을 때는 항상 주의해야 해. 악의적인 입력을 통해 시스템을 공격할 수 있거든. 예를 들어, SQL 인젝션 같은 공격을 막으려면 이렇게 할 수 있어:
using System.Data.SqlClient;
string userInput = "Robert'); DROP TABLE Users;--"; // 악의적인 입력
string safeQuery = "SELECT * FROM Users WHERE Name = @Name";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(safeQuery, connection);
command.Parameters.AddWithValue("@Name", userInput);
// 이후 쿼리 실행
}
매개변수화된 쿼리를 사용하면 SQL 인젝션 공격을 효과적으로 막을 수 있어. 재능넷 같은 플랫폼에서 사용자 정보를 다룰 때 이런 방식을 꼭 사용해야 해!
민감한 정보 다루기 🕵️♀️
비밀번호 같은 민감한 정보를 다룰 때는 특별히 주의해야 해. 일반 문자열 대신 SecureString
클래스를 사용하는 게 좋아:
using System.Security;
SecureString securePassword = new SecureString();
foreach (char c in "MySecretPassword")
{
securePassword.AppendChar(c);
}
securePassword.MakeReadOnly();
// 사용 후에는 반드시 Dispose 호출
securePassword.Dispose();
SecureString
은 메모리에서 암호화된 상태로 저장되기 때문에, 일반 문자열보다 더 안전해.
정규 표현식 사용 시 주의사항 ⚠️
정규 표현식은 강력하지만, 잘못 사용하면 보안 문제를 일으킬 수 있어. 특히 사용자 입력을 그대로 정규 표현식에 사용하면 위험해:
string userInput = "^(a+)+$"; // 악의적인 입력
string text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!";
// 이렇게 하면 안 돼!
// if (Regex.IsMatch(text, userInput)) { ... }
// 대신 이렇게 해:
if (Regex.IsMatch(text, userInput, RegexOptions.None, TimeSpan.FromSeconds(1)))
{
// 매칭 성공
}
시간 제한을 설정하면 악의적인 정규 표현식으로 인한 과도한 CPU 사용을 막을 수 있어.
8. 문자열과 인코딩 🔡
문자열을 다룰 때 문자열을 다룰 때 인코딩을 이해하는 것도 중요해. 특히 여러 언어를 지원하는 프로그램을 만들 때는 더욱 그렇지. 자, 이어서 알아볼까?
문자 인코딩 이해하기 📚
문자 인코딩은 컴퓨터가 문자를 저장하고 표현하는 방식이야. C#에서는 기본적으로 UTF-16 인코딩을 사용하지만, 다른 인코딩도 사용할 수 있어:
using System.Text;
string message = "안녕하세요";
// UTF-8로 인코딩
byte[] utf8Bytes = Encoding.UTF8.GetBytes(message);
// UTF-8에서 다시 문자열로 디코딩
string decodedMessage = Encoding.UTF8.GetString(utf8Bytes);
Console.WriteLine(decodedMessage); // 출력: 안녕하세요
이렇게 하면 다양한 인코딩 간에 문자열을 변환할 수 있어. 재능넷 같은 글로벌 플랫폼에서는 다양한 언어와 문자를 처리해야 하니까 이런 기능이 꼭 필요하겠지?
BOM (Byte Order Mark) 다루기 🏁
BOM은 텍스트 파일의 시작 부분에 있는 특별한 마커야. 이걸 통해 파일의 인코딩을 알 수 있지. C#에서는 이렇게 다룰 수 있어:
string filePath = "example.txt";
// BOM과 함께 UTF-8로 파일 쓰기
using (StreamWriter writer = new StreamWriter(filePath, false, new UTF8Encoding(true)))
{
writer.Write("Hello, World!");
}
// BOM을 확인하며 파일 읽기
using (StreamReader reader = new StreamReader(filePath, true))
{
Console.WriteLine($"인코딩: {reader.CurrentEncoding}");
Console.WriteLine(reader.ReadToEnd());
}
이렇게 하면 BOM을 포함한 파일을 쓰고 읽을 수 있어. 국제화된 애플리케이션에서 파일을 다룰 때 유용하지.
문자열과 바이트 배열 변환 🔄
때로는 문자열을 바이트 배열로, 또는 그 반대로 변환해야 할 때가 있어. 이럴 때는 이렇게 할 수 있어:
string original = "Hello, 안녕하세요!";
// 문자열을 바이트 배열로 변환
byte[] bytes = Encoding.UTF8.GetBytes(original);
// 바이트 배열을 다시 문자열로 변환
string roundTrip = Encoding.UTF8.GetString(bytes);
Console.WriteLine(roundTrip); // 출력: Hello, 안녕하세요!
이 기능은 네트워크 통신이나 파일 입출력에서 자주 사용돼. 재능넷에서 사용자 데이터를 저장하거나 전송할 때 이런 변환이 필요할 거야.
9. 문자열 처리의 최신 트렌드 🚀
C# 언어와 .NET 프레임워크는 계속 발전하고 있어. 최신 버전에서는 문자열 처리를 위한 새로운 기능들이 추가됐어. 몇 가지 살펴볼까?
Span<T>와 문자열 처리 🏃♂️
Span<T>
는 C# 7.2에서 도입된 구조체야. 메모리의 연속된 영역을 나타내는데, 문자열 처리에도 사용할 수 있어:
string text = "Hello, World!";
ReadOnlySpan<char> span = text.AsSpan();
// 부분 문자열 얻기
var part = span.Slice(0, 5);
Console.WriteLine(part.ToString()); // 출력: Hello
// 문자 찾기
int index = span.IndexOf('W');
Console.WriteLine(index); // 출력: 7
</char>
Span<T>
를 사용하면 문자열 처리 성능을 크게 향상시킬 수 있어. 특히 대용량 데이터를 다룰 때 유용하지.
문자열 보간의 새로운 기능 💬
C# 10에서는 문자열 보간에 새로운 기능이 추가됐어. 상수 문자열을 보간할 수 있게 된 거지: