.NET 라이브러리
String과 텍스트 핸들링
문자(Char) 다루기
- 문자(Char)는 단일 유니코드 문자를 나타내는 기본 구조체임. 16비트 크기를 가지며 System.Char 구조체에 대한 별칭임.
- 기본적인 문자 리터럴 표현
char c = 'A';
char newLine = '\\n'; // 특수 문자
- 주요 정적 메서드들
- ToUpper(), ToLower(): 대소문자 변환
- IsWhiteSpace(): 공백 문자 여부 확인
- IsLetter(), IsDigit(): 문자, 숫자 여부 확인
Console.WriteLine(char.ToUpper('c')); // 출력: C
Console.WriteLine(char.IsWhiteSpace('\\t')); // 출력: True
Console.WriteLine(char.IsLetter('A')); // 출력: True
Console.WriteLine(char.IsDigit('5')); // 출력: True
문자열(String) 다루기
- 문자열(String)은 일련의 문자들을 나타내는 참조 형식임. 불변(Immutable) 특성을 가짐.
- 불변 : 인스턴스를 만들면 값변경이 안되는 속성이다.
- 새로운 인스턴스를 참조하는 식으로 변경된다.
- 문자열 : 클래스이기에 ‘참조 형식’이다.
- 문자열 생성 방법
// 직접 할당
string s1 = "Hello";
// 반복 문자로 생성
string stars = new string('*', 10); // **********
// 문자 배열로 생성
char[] ca = "Hello".ToCharArray();
string s2 = new string(ca);
- null과 빈 문자열
string empty = ""; // 빈 문자열
string empty2 = string.Empty; // 위와 동일
string nullString = null; // null 문자열
Console.WriteLine(empty == ""); // True
Console.WriteLine(nullString == null); // True
Console.WriteLine(nullString == ""); // False
- 문자열 검색
string text = "quick brown fox";
// 문자열 시작, 포함 여부 확인
Console.WriteLine(text.StartsWith("quick")); // True
Console.WriteLine(text.Contains("brown")); // True
// 위치 찾기
Console.WriteLine(text.IndexOf("fox")); // 12 / fox가 시작하는 인덱스 반환
문자열 조작
- 문자열의 불변성으로 인해 모든 조작 메서드는 새로운 문자열을 반환함.
// 부분 문자열 추출
string numbers = "12345";
string left3 = numbers.Substring(0, 3); // "123" / 시작 인덱스부터 몇개 추출
string mid3 = numbers.Substring(1, 3); // "234"
// 삽입과 제거
string s1 = "helloworld".Insert(5, ", "); // "hello, world" / 인덱스 뒤에 추가
string s2 = s1.Remove(5, 2); // "helloworld" / 인덱스 뒤부터 몇개 제거
// 패딩
Console.WriteLine("12345".PadLeft(9, '*')); // ****12345 / 총 길이, 추가할 문자
Console.WriteLine("12345".PadRight(9, '*')); // 12345****
// 공백 삭제
Console.WriteLine (" abc \\t\\r\\n ".Trim().Length); // 3
Console.WriteLine("Trim() : '{0}'", " No Spaces ".Trim());
Console.WriteLine("TrimStart() : '{0}'", " No Spaces ".TrimStart());
Console.WriteLine("TrimEnd() : '{0}'", " No Spaces ".TrimEnd());
// Replace
Console.WriteLine ("to be done".Replace (" ", " | ") ); // to | be | done
Console.WriteLine ("to be done".Replace (" ", "") ); // tobedone
// 기본 동작: 공백 기준으로 문자열 자르기
string[] words = "The quick brown fox".Split();
foreach (string word in words)
Console.Write (word + "|"); // The|quick|brown|fox
- Trim : 공백 문자 앞뒤 제거
- \r , \t , \n 을 공백으로 판단한다.
- 앞과 뒤의 공백을 제거하는것이니 중간 공백은 지우지 못한다.
- Replace : 바꿀 문자, 대체할 문자
StringBuilder 사용
- StringBuilder는 가변 문자열을 다루는 클래스임. 문자열 연결 작업이 많을 때 성능 향상을 위해 사용함.
StringBuilder sb = new StringBuilder();
// 문자열 추가
for (int i = 0; i < 10; i++)
{
sb.Append(i).Append(",");
}
Console.WriteLine(sb.ToString()); // "0,1,2,3,4,5,6,7,8,9,"
// 줄 추가
StringBuilder sb2 = new StringBuilder();
sb2.AppendLine("First line");
sb2.AppendLine("Second line");
Console.WriteLine(sb2.ToString());
// 문자열 삽입과 제거
StringBuilder sb3 = new StringBuilder("Hello World");
sb3.Insert(5, " Beautiful"); // "Hello Beautiful World"
sb3.Remove(5, 10); // "Hello World"
- Append(문자) : 들어온 문자를 계속 연결하는 함수다.
- string + 연산자의 역할이다.
- string에서 + 연산자를 쓰지 말아야할 이유 : 호출할때마다 가비지 컬렉터가 계속 동작해야하기 때문이다.
- 따라서, 문자열 연결이 있을 시 StringBuilder를 사용해라
문자열 포맷팅
- 문자열 포맷팅(String Formatting)은 문자열에 데이터를 삽입하여 원하는 형식으로 표현하는 방법임
- String.Format() 메서드를 사용하거나 복합 포맷 문자열을 활용함
String.Format 메서드
- 기본 사용법:
string name = "홍길동"; int age = 20; double height = 175.5; // 여러 값을 하나의 문자열로 조합 string info = string.Format( "이름: {0}\\n나이: {1}세\\n키: {2:F1}cm", //F1 : 소수점 1자리까지만 출력 name, age, height); Console.WriteLine(info); // 동일한 값을 여러 번 사용 string repeated = string.Format( "{0}님 안녕하세요! {0}님의 나이는 {1}세입니다.", name, age); Console.WriteLine(repeated); // 출력: // 이름: 홍길동 // 나이: 20세 // 키: 175.5cm // 홍길동님 안녕하세요! 홍길동님의 나이는 20세입니다. - string composite = "It's {0} degrees in {1} on this {2} morning"; //서식 문자열 string result = string.Format(composite, 35, "Perth", DateTime.Now.DayOfWeek); Console.WriteLine(result); // 출력: It's 35 degrees in Perth on this Friday morning
- 보간 문자열(Interpolated string) 사용:
- string result = $"It's hot this {DateTime.Now.DayOfWeek} morning"; Console.WriteLine(result); // 출력: It's hot this Friday morning
숫자 포맷팅
소수점 자릿수 제한
double price = 123.4567;
Console.WriteLine($"금액: {price:F2}"); // 금액: 123.46
Console.WriteLine($"금액: {price:N2}"); // 금액: 123.46 (천단위 구분기호 포함)
Console.WriteLine(string.Format("금액: {0:F4}", price)); // 금액: 123.4567
백분율 표시
double ratio = 0.175;
Console.WriteLine($"비율: {ratio:P0}"); // 비율: 18%
Console.WriteLine($"비율: {ratio:P1}"); // 비율: 17.5%
통화 표시
decimal money = 12345.6789m;
Console.WriteLine($"통화: {money:C}"); // 통화: ₩12,346
Console.WriteLine($"통화: {money:C3}"); // 통화: ₩12,345.679
16진수 표시
int value = 255;
Console.WriteLine($"16진수(소문자): {value:x}"); // 16진수(소문자): ff
Console.WriteLine($"16진수(대문자): {value:X}"); // 16진수(대문자): FF
Console.WriteLine($"16진수(4자리): {value:X4}"); // 16진수(4자리): 00FF
포맷 항목 구조와 정렬
최소 너비 지정과 정렬
// 왼쪽 정렬(-), 오른쪽 정렬(+)
string header = string.Format("{0,-10} {1,10}", "이름", "점수");
string row1 = string.Format("{0,-10} {1,10:N0}", "김철수", 95);
string row2 = string.Format("{0,-10} {1,10:N0}", "이영희", 100);
Console.WriteLine(header);
Console.WriteLine(row1);
Console.WriteLine(row2);
// 출력:
// 이름 점수
// 김철수 95
// 이영희 100
날짜와 시간 포맷팅
DateTime now = DateTime.Now;
/[]p'\\
Console.WriteLine($"기본: {now}"); // 2024-12-18 14:30:45
Console.WriteLine($"short date: {now:d}"); // 2024-12-18
Console.WriteLine($"long date: {now:D}"); // 2024년 12월 18일 수요일
Console.WriteLine($"short time: {now:t}"); // 14:30
Console.WriteLine($"custom: {now:yyyy-MM-dd HH:mm}"); // 2024-12-18 14:30
숫자 자릿수 맞추기
for (int i = 1; i <= 12; i++)
{
Console.WriteLine($"Chapter {i:D2}"); // 01부터 12까지 두 자리로 표시
}
// 출력:
// Chapter 01
// Chapter 02
// ...
// Chapter 12
날짜와 시간 다루기
TimeSpan 활용
TimeSpan은 시간 간격을 나타내는 구조체임. 게임에서 경과 시간, 쿨타임 등을 구현할 때 유용함.
- 생성 방법
// 생성자 사용
TimeSpan t1 = new TimeSpan(2, 30, 0); // 2시간 30분
// 정적 메서드 사용
TimeSpan t2 = TimeSpan.FromHours(2.5); // 2.5시간
TimeSpan t3 = TimeSpan.FromMinutes(150); // 150분
- 시간 계산
TimeSpan cooldown = TimeSpan.FromSeconds(30);
TimeSpan elapsed = TimeSpan.FromSeconds(20);
// 남은 시간 계산
TimeSpan remaining = cooldown - elapsed; // 10초
// 시간 요소 접근
Console.WriteLine(remaining.TotalSeconds); // 10
Console.WriteLine(remaining.Seconds); // 10
DateTime 활용
DateTime은 특정 날짜와 시간을 나타내는 구조체임. 게임의 저장/로드 시간, 이벤트 시간 등을 다룰 때 사용함.
- DateTime 포맷팅
DateTime eventTime = new DateTime(2024, 12, 25);
// 기본 포맷
Console.WriteLine(eventTime.ToString()); // 2024-12-25 00:00:00
// 사용자 지정 포맷
Console.WriteLine(eventTime.ToString("yyyy-MM-dd")); // 2024-12-25
Console.WriteLine(eventTime.ToString("MM/dd/yyyy HH:mm")); // 12/25/2024 00:00
// 게임에서 자주 사용하는 포맷
Console.WriteLine(eventTime.ToString("M")); // 12월 25일
Console.WriteLine(eventTime.ToString("t")); // 00:00
- 기본 사용
// 특정 날짜/시간 생성
DateTime gameStartTime = new DateTime(2024, 1, 1, 12, 0, 0);
// 현재 시간
DateTime now = DateTime.Now;
// 날짜 연산
DateTime end = now.AddHours(2); // 2시간 후
TimeSpan duration = end - now; // 기간 계산
- 게임에서의 활용: 쿨타임 시스템
public class Skill
{
private TimeSpan cooldown = TimeSpan.FromSeconds(30);
private DateTime? lastUsedTime = null;
public bool CanUse()
{
if (lastUsedTime == null) return true;
TimeSpan elapsed = DateTime.Now - lastUsedTime.Value;
return elapsed >= cooldown;
}
public void Use()
{
if (CanUse())
{
Console.WriteLine("스킬 사용!");
lastUsedTime = DateTime.Now;
}
else
{
TimeSpan remaining = cooldown -
(DateTime.Now - lastUsedTime.Value);
Console.WriteLine($"아직 {remaining.TotalSeconds:F1}초 남음");
}
}
}
수치 처리와 수학
Math 클래스 활용
- Math 클래스는 기본적인 수학 연산을 제공하는 정적 클래스임.
- 유니티는 Mathf 클래스가 따로 있다
// 반올림, 올림, 내림
double d = 3.7;
Console.WriteLine(Math.Round(d)); // 4 //반올림
Console.WriteLine(Math.Floor(d)); // 3 / 내림
Console.WriteLine(Math.Ceiling(d)); // 4 / 올림
// 최대값, 최소값, 절대값
Console.WriteLine(Math.Max(10, 20)); // 20
Console.WriteLine(Math.Min(10, 20)); // 10
Console.WriteLine(Math.Abs(-50)); // 50
// 제곱, 제곱근, 삼각함수
Console.WriteLine(Math.Pow(2, 3)); // 8
Console.WriteLine(Math.Sqrt(16)); // 4
Console.WriteLine(Math.Sin(Math.PI / 2)); // 1 / 라디안 단위다.
BigInteger 활용
- BigInteger는 임의 크기의 정수를 다룰 수 있는 구조체임. 매우 큰 수치가 필요한 게임에서 유용함.
- 방치형 게임에서 사용된다. - 수치 자릿수가 크기 때문이다.
using System.Numerics;
// BigInteger 생성과 연산
BigInteger exp = BigInteger.Parse("999999999999999999999999999");
BigInteger gold = new BigInteger(1000000);
gold *= 1000000; // 매우 큰 수로 증가
// 게임 예제: 클리커 게임
public class ClickerGame
{
private BigInteger score = 0;
private BigInteger clickPower = 1;
public void Click()
{
score += clickPower;
Console.WriteLine($"현재 점수: {score:N0}");
}
public void UpgradeClickPower()
{
clickPower *= 2;
Console.WriteLine($"클릭 파워 증가! 현재: {clickPower:N0}");
}
}
암호학적으로 안전한 난수 생성
보안이 중요한 부분(예: 확률형 아이템)에서는 암호학적으로 안전한 난수를 사용할 수 있음.
using System.Security.Cryptography;
// 안전한 난수 생성
byte[] bytes = new byte[32];
RandomNumberGenerator.Fill(bytes);
// 1-100 사이의 안전한 난수 얻기
int secureRandom = (bytes[0] % 100) + 1;
Console.WriteLine($"보안 난수: {secureRandom}");
Random 클래스 활용
- Random 클래스는 의사 난수를 생성하는데 사용됨.
- 가산 함수 : 시드 같은 특정 숫자 또는 불규칙적인 수를 반환하는 함수를 의미한다.
Random rand = new Random();
// 정수 범위의 난수
Console.WriteLine(rand.Next(1, 101)); // 1-100 사이
// 실수 범위의 난수
Console.WriteLine(rand.NextDouble()); // 0.0-1.0 사이
// 게임 예제: 아이템 드롭 시스템
public class ItemDropSystem
{
private Random rand = new Random();
public bool TryDropItem(double dropRate)
{
return rand.NextDouble() < dropRate;
}
public int GetRandomDamage(int minDamage, int maxDamage)
{
return rand.Next(minDamage, maxDamage + 1);
}
}
객체 비교와 정렬
객체 비교의 기본 개념
- 값 형식(struct)은 기본적으로 값 비교를 수행함
- 참조 형식(class)은 기본적으로 참조 비교를 수행함
- 2개의 참조형식 비교가 같은 인스턴스를 참조하고 있는지 확인하는 것이다.
- 하지만, string 클래스틑 참조 형식이지만, == 같다 비교는 ‘값 형식’으로 비교를 진행한다.
// 값 비교 예시
int x = 5, y = 5;
Console.WriteLine(x == y); // True
// 참조 비교 예시
class Player { public int Id; }
Player p1 = new Player { Id = 5 };
Player p2 = new Player { Id = 5 };
Console.WriteLine(p1 == p2); // False
Equals와 GetHashCode 구현
- 객체의 동등성 비교를 위해서는 Equals와 GetHashCode를 함께 구현해야 함.
public class GameItem
{
public string Name { get; set; }
public int Level { get; set; }
//값 비교를 위한 Equals 재구현
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
GameItem other = (GameItem)obj;
return Name == other.Name && Level == other.Level;
}
public override int GetHashCode()
{
return HashCode.Combine(Name, Level);
}
}
- Equals : bool형 리턴
- GetHashCode : 입력값이 같다면 동일한 결과를 반환한다.
IComparable 구현
- 객체의 정렬 순서를 정의하려면 IComparable 인터페이스를 구현함.
public class Score : IComparable<Score>
{
public string PlayerName { get; set; }
public int Points { get; set; }
//정렬 기준이 같은지 확인하는 함수기에, 결과가 다를 수 있다.
public int CompareTo(Score other)
{
if (other == null) return 1;
return other.Points.CompareTo(Points); // 내림차순 정렬
}
}
// 사용 예시
var scores = new List<Score>
{
new Score { PlayerName = "Alice", Points = 100 },
new Score { PlayerName = "Bob", Points = 150 },
new Score { PlayerName = "Charlie", Points = 120 }
};
scores.Sort();
// 결과: Bob(150) > Charlie(120) > Alice(100)
게임 예제: 아이템 인벤토리 시스템
아이템 동등성 비교와 해시 기능을 활용한 실전적인 인벤토리 시스템 예제.
public class InventoryItem : IEquatable<InventoryItem>
{
public string Id { get; set; }
public string Name { get; set; }
public int Count { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as InventoryItem);
}
public bool Equals(InventoryItem other)
{
if (other == null) return false;
return Id == other.Id; // ID만으로 동일성 판단
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
public class Inventory
{
private HashSet<InventoryItem> items = new HashSet<InventoryItem>();
public bool AddItem(InventoryItem item)
{
return items.Add(item); // 중복 아이템은 추가되지 않음
}
public void DisplayItems()
{
foreach (var item in items)
{
Console.WriteLine($"{item.Name} x{item.Count}");
}
}
}
// 사용 예시
var inventory = new Inventory();
inventory.AddItem(new InventoryItem { Id = "SWORD1", Name = "강철검", Count = 1 });
inventory.AddItem(new InventoryItem { Id = "POTION1", Name = "체력 포션", Count = 5 });
// 중복 아이템 추가 시도
inventory.AddItem(new InventoryItem { Id = "SWORD1", Name = "강철검", Count = 1 });
inventory.DisplayItems();
// 출력:
// 강철검 x1
// 체력 포션 x5
'공부 > C#' 카테고리의 다른 글
| Array Class, Lists, Queues, Stacks, Sets (7) | 2025.08.26 |
|---|---|
| Enumeration, IEnumerator, 이터레이터 사용, ICollection, IList, 읽기 전용 인터페이스, 배열 클래스 (8) | 2025.08.26 |
| 연산자 오버로딩, 전처리기 (2) | 2025.08.25 |
| 익명 타입, 튜플, 레코드, 패턴, 어트리뷰트 (4) | 2025.08.25 |
| Nullable, 확장 메서드, 메서드 체이닝 (0) | 2025.08.19 |