[C#/COMMON/.NET8] 대용량 CSV 파일 병합하기
■ 대용량 CSV 파일을 병합하는 방법을 보여준다. ※ CSV 파일에 헤더 라인이 있어야 합니다. ※ 병합하는 CSV 파일은 동일한 헤더 라인을 갖고
■ 대용량 CSV 파일을 병합하는 방법을 보여준다. ※ CSV 파일에 헤더 라인이 있어야 합니다. ※ 병합하는 CSV 파일은 동일한 헤더 라인을 갖고
■ sample 함수를 사용해 임의의 문자 리스트를 구하는 방법을 보여준다. ▶ 예제 코드 (PY)
1 2 3 4 5 6 7 8 9 10 11 12 |
import random import string stringList = random.sample(list(string.ascii_lowercase), 25) print(stringList) """ ['e', 'x', 'h', 'o', 'j', 'd', 'q', 'm', 'b', 'v', 'w', 'k', 'l', 'r', 's', 'u', 'i', 'g', 'a', 'f', 'n', 'z', 'c', 'p', 't'] """ |
■ ascii_lowercase 변수를 사용해 알파벳 소문자 문자열을 구하는 방법을 보여준다. ▶ 예제 코드 (PY)
1 2 3 4 5 6 7 8 9 10 11 |
import string asciiLowercaseString = string.ascii_lowercase print(asciiLowercaseString) """ abcdefghijklmnopqrstuvwxyz """ |
■ HttpClient 클래스를 사용해 OLLAMA 서버와 통신하는 방법을 보여준다. ▶ OllamaRequest.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using System.Text.Json.Serialization; namespace TestProject; /// <summary> /// OLLAMA 요청 /// </summary> public class OllamaRequest { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 모델 - Model /// <summary> /// 모델 /// </summary> [JsonPropertyName("model")] public string Model { get; set; } #endregion #region 프롬프트 - Prompt /// <summary> /// 프롬프트 /// </summary> [JsonPropertyName("prompt")] public string Prompt { get; set; } #endregion #region 스트림 여부 - Stream /// <summary> /// 스트림 여부 /// </summary> [JsonPropertyName("stream")] public bool Stream { get; set; } #endregion } |
▶ OllamaResponse.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
using System.Text.Json.Serialization; namespace TestProject; /// <summary> /// OLLAMA 응답 /// </summary> public class OllamaResponse { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 모델 - Model /// <summary> /// 모델 /// </summary> [JsonPropertyName("model")] public string Model { get; set; } #endregion #region 응답 - Response /// <summary> /// 응답 /// </summary> [JsonPropertyName("response")] public string Response { get; set; } #endregion #region 완료 여부 - Done /// <summary> /// 완료 여부 /// </summary> [JsonPropertyName("done")] public bool Done { get; set; } #endregion } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
using System; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace TestProject; /// <summary> /// 프로그램 /// </summary> public class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region OLLAMA 요청 보내기 (비동기) - SendOllamaRequestAsync(httpClient, ollamaRequest) /// <summary> /// OLLAMA 요청 보내기 (비동기) /// </summary> /// <param name="httpClient">HTTP 클라이언트</param> /// <param name="ollamaRequest">OLLAMA 요청</param> /// <returns>OLLAMA 응답 태스크</returns> private static async Task<OllamaResponse> SendOllamaRequestAsync(HttpClient httpClient, OllamaRequest ollamaRequest) { string json = JsonSerializer.Serialize ( ollamaRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase } ); StringContent stringContent = new StringContent(json, Encoding.UTF8, "application/json"); HttpResponseMessage response = await httpClient.PostAsync("/api/generate", stringContent); response.EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize<OllamaResponse> ( responseBody, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase } ); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private static async Task Main() { string baseURL = "http://localhost:11434"; using var httpClient = new HttpClient(); httpClient.BaseAddress = new Uri(baseURL); OllamaRequest ollamaRequest = new() { Model = "bnksys/eeve-yanolja-v1:latest", Prompt = "여기어때와 야놀자의 차이점을 알려주세요.", Stream = false }; try { OllamaResponse ollamaResponse = await SendOllamaRequestAsync(httpClient, ollamaRequest); Console.WriteLine($"질문 : {ollamaRequest.Prompt }"); Console.WriteLine($"응답 : {ollamaResponse.Response}"); } catch(Exception exception) { Console.WriteLine($"오류 발생 : {exception.Message}"); } } #endregion } |
TestProject.zip
■ RegistryKey 클래스를 사용해 CUDA 설치 여부 및 CUDA 버전을 구하는 방법을 보여준다. ▶ CUDAHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
using Microsoft.Win32; namespace TestProject; /// <summary> /// CUDA 헬퍼 /// </summary> public class CUDAHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region CUDA 설치 여부 구하기 - IsCUDAInstalled() /// <summary> /// CUDA 설치 여부 구하기 /// </summary> /// <returns>CUDA 설치 여부</returns> public static bool IsCUDAInstalled() { try { #pragma warning disable CA1416 // 플랫폼 호환성 유효성 검사 using(RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\NVIDIA Corporation\GPU Computing Toolkit\CUDA")) { if(registryKey != null) { string[] subkeyNameArray = registryKey.GetSubKeyNames(); if(subkeyNameArray.Length > 0) { return true; } } } #pragma warning restore CA1416 // 플랫폼 호환성 유효성 검사 return false; } catch { return false; } } #endregion #region CUDA 버전 구하기 - GetGUDAVersion() /// <summary> /// CUDA 버전 구하기 /// </summary> /// <returns>CUDA 버전</returns> public static string GetGUDAVersion() { if(IsCUDAInstalled()) { #pragma warning disable CA1416 // 플랫폼 호환성 유효성 검사 using(RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\NVIDIA Corporation\GPU Computing Toolkit\CUDA")) { if(registryKey != null) { string[] subkeyNameArray = registryKey.GetSubKeyNames(); if(subkeyNameArray.Length > 0) { string version = string.Join(", ", subkeyNameArray); return version; } } } #pragma warning restore CA1416 // 플랫폼 호환성 유효성 검사 return null; } else { return null; } } #endregion } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
using System; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> static void Main() { bool isCUDAInstalled = CUDAHelper.IsCUDAInstalled(); if(isCUDAInstalled) { Console.WriteLine("CUDA가 설치되어 있습니다."); string version = CUDAHelper.GetGUDAVersion(); Console.WriteLine($"CUDA 버전 : {version}"); } else { Console.WriteLine("CUDA가 설치되어 있지 않습니다."); } } #endregion } |
TestProject.zip
■ HtmlDocument 클래스를 사용해 HTML 문자열에서 텍스트를 추출하는 방법을 보여준다. ▶ HTMLHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
using System; using System.Linq; using System.Text.RegularExpressions; using HtmlAgilityPack; /// <summary> /// HTML 헬퍼 /// </summary> public class HTMLHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 텍스트 추출하기 - ExtractText(html) /// <summary> /// 텍스트 추출하기 /// </summary> /// <param name="html">HTML</param> /// <returns>텍스트</returns> public static string ExtractText(string html) { HtmlDocument htmlDocument = new HtmlDocument(); htmlDocument.LoadHtml(html); return htmlDocument.DocumentNode.InnerText; } #endregion #region 문자열 정규화하기 - NormalizeString(sourceString) /// <summary> /// 문자열 정규화하기 /// </summary> /// <param name="sourceString">소스 문자열</param> /// <returns>정규화 문자열</returns> /// <remarks> /// 1. 각 줄의 문자열의 앞뒤 공백을 제거한다. /// 2. 빈줄이 반복되는 경우 1개의 빈줄로 만든다. /// </remarks> public static string NormalizeString(string sourceString) { string[] sourceLineArray = sourceString.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); string[] targetLineArray = sourceLineArray.Select(line => line.Trim()).ToArray(); string joinedString = string.Join(Environment.NewLine, targetLineArray); string targetString = Regex.Replace(joinedString, @"(\r\n|\n){2,}", Environment.NewLine + Environment.NewLine); return targetString; } #endregion } |
※ HtmlAgilityPack 누겟 패키지를 설치한다.
■ String 클래스에서 문자열을 정규화하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System; using System.Linq; using System.Text.RegularExpressions; #region 문자열 정규화하기 - NormalizeString(sourceString) /// <summary> /// 문자열 정규화하기 /// </summary> /// <param name="sourceString">소스 문자열</param> /// <returns>정규화 문자열</returns> /// <remarks> /// 1. 각 줄의 문자열의 앞뒤 공백을 제거한다. /// 2. 빈줄이 반복되는 경우 1개의 빈줄로 만든다. /// </remarks> public string NormalizeString(string sourceString) { string[] sourceLineArray = sourceString.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); string[] targetLineArray = sourceLineArray.Select(line => line.Trim()).ToArray(); string joinedString = string.Join(Environment.NewLine, targetLineArray); string targetString = Regex.Replace(joinedString, @"(\r\n|\n){2,}", Environment.NewLine + Environment.NewLine); return targetString; } #endregion |
■ String 클래스에서 문자열을 정규화하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using System; using System.Collections.Generic; #region 텍스트 정규화하기 - NormalizeText(sourceString) /// <summary> /// 텍스트 정규화하기 /// </summary> /// <param name="sourceString">소스 문자열</param> /// <returns>정규화 텍스트</returns> /// <remarks> /// 1. 각 줄의 문자열의 앞뒤 공백을 제거한다. /// 2. 빈줄이 반복되면 1개의 빈줄로 만든다. /// 3. 문자열이 있는 줄들 사이에 빈줄을 추가한다. /// </remarks> public string NormalizeText(string sourceString) { string[] sourceLineArray = sourceString.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); List<string> targetList = new List<string>(); bool previousLineWasEmpty = false; foreach(string sourceLine in sourceLineArray) { string targetLine = sourceLine.Trim(); if (string.IsNullOrEmpty(targetLine)) { if(!previousLineWasEmpty) { targetList.Add(string.Empty); previousLineWasEmpty = true; } } else { targetList.Add(targetLine); previousLineWasEmpty = false; } } return string.Join(Environment.NewLine, targetList); } #endregion |
■ uuid4 함수를 사용해 UUID(GUID) 문자열을 구하는 방법을 보여준다. ▶ 예제 코드 (PY)
1 2 3 4 5 6 7 8 9 |
import uuid uuid1 = uuid.uuid4() uuidString = str(uuid1).upper() print(uuidString) |
■ uuid4 함수를 사용해 UUID 객체를 만드는 방법을 보여준다. ▶ 예제 코드 (PY)
1 2 3 4 5 |
import uuid uuid1 = uuid.uuid4() |
■ FSK (Frequency Shift Keying) 변조를 사용하는 방법을 보여준다. [Encoder 프로젝트] ▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
using System; using System.IO; using System.Linq; using System.Numerics; using System.Text; using NAudio.Wave; namespace DECODER; /// <summary> /// 디코더 /// </summary> class Decoder { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 다음 2의 거듭 제곱 구하기 - NextPowerOfTwo(value) /// <summary> /// 다음 2의 거듭 제곱 구하기 /// </summary> /// <param name="value">값</param> /// <returns></returns> /// <remarks>입력값보다 큰 가장 작은 2의 거듭 제곱을 계산한다.</remarks> private static int NextPowerOfTwo(int value) { int power = 1; while(power < value) { power <<= 1; } return power; } #endregion #region 비트 반전하기 - BitReverse(bitValue, bitCount) /// <summary> /// 비트 반전하기 /// </summary> /// <param name="bitValue">비트 값</param> /// <param name="bitCount">비트 수</param> /// <returns>반전 비트 값</returns> private static int BitReverse(int bitValue, int bitCount) { int reversed = 0; for(int i = 0; i < bitCount; i++) { int nextBit = (bitValue >> i) & 1; reversed |= (nextBit << (bitCount - i - 1)); } return reversed; } #endregion #region FFT 처리하기 - FFT(complexArray) /// <summary> /// FFT 처리하기 /// </summary> /// <param name="complexArray">복소수 배열</param> private static void FFT(Complex[] complexArray) { int complexArrayLength = complexArray.Length; if(complexArrayLength <= 1) { return; } // Bit reversal permutation int m1 = (int)Math.Log(complexArrayLength, 2); for(int i = 0; i < complexArrayLength; i++) { int j = BitReverse(i, m1); if(j > i) { Complex t = complexArray[i]; complexArray[i] = complexArray[j]; complexArray[j] = t; } } // Cooley-Tukey FFT for(int s = 1; s <= m1; s++) { int m2 = 1 << s; Complex wm = Complex.Exp(-2.0 * Math.PI * Complex.ImaginaryOne / m2); for(int k = 0; k < complexArrayLength; k += m2) { Complex w = 1; for(int j = 0; j < m2 / 2; j++) { int index1 = k + j; int index2 = k + j + m2 / 2; Complex t = w * complexArray[index2]; Complex u = complexArray[index1]; complexArray[index1] = u + t; complexArray[index2] = u - t; w *= wm; } } } } #endregion #region 프로그램 시작하기 - Main(argumentArray) /// <summary> /// 프로그램 시작하기 /// </summary> /// <param name="argumentArray">인자 배열</param> private static void Main(string[] argumentArray) { if(argumentArray.Length != 2) { Console.WriteLine("사용법 : decoder.exe source.wav target.zip"); return; } string sourceFilePath = argumentArray[0]; string targetFilePath = argumentArray[1]; int samplingFrequency = 44100; // 샘플링 주파수 double durationPerBit = 0.01; // 각 비트의 지속 시간 (초) int sampleCountPerBit = (int)(samplingFrequency * durationPerBit); int frequency0 = 1000; // '0'에 대한 주파수 int frequency1 = 2000; // '1'에 대한 주파수 // 시작 및 종료 마커를 설정한다. string startMarkerBitString = "1111000011110000"; string endMarkerBitString = "0000111100001111"; // WAV 파일을 읽는다. float[] signalArray; using(AudioFileReader audioFileReader = new(sourceFilePath)) { int totalSampleCount = (int)audioFileReader.Length / (audioFileReader.WaveFormat.BitsPerSample / 8); signalArray = new float[totalSampleCount]; int readSampleCount = audioFileReader.Read(signalArray, 0, totalSampleCount); } int bitCount = signalArray.Length / sampleCountPerBit; StringBuilder bitStringBuilder = new StringBuilder(); for(int i = 0; i < bitCount; i++) { int start = i * sampleCountPerBit; int end = start + sampleCountPerBit; if(end > signalArray.Length) { break; } float[] segmentArray = new float[sampleCountPerBit]; Array.Copy(signalArray, start, segmentArray, 0, sampleCountPerBit); // 입력 배열 길이를 가장 가까운 2의 거듭제곱으로 패딩한다. int paddedLength = NextPowerOfTwo(segmentArray.Length); Complex[] fftComplexArray = new Complex[paddedLength]; for(int j = 0; j < segmentArray.Length; j++) { fftComplexArray[j] = new Complex(segmentArray[j], 0); } for(int j = segmentArray.Length; j < paddedLength; j++) { fftComplexArray[j] = Complex.Zero; } // 주파수 분석을 위한 FFT를 수행한다. FFT(fftComplexArray); double[] magnitudeArray = fftComplexArray.Take(paddedLength / 2).Select(c => c.Magnitude).ToArray(); int peakIndex = Array.IndexOf(magnitudeArray, magnitudeArray.Max()); double peakFrequency = (double)peakIndex * samplingFrequency / paddedLength; // 주파수에 따라 비트를 결정한다. if(Math.Abs(peakFrequency - frequency0) < 100) { bitStringBuilder.Append('0'); } else if(Math.Abs(peakFrequency - frequency1) < 100) { bitStringBuilder.Append('1'); } else { bitStringBuilder.Append('?'); } } string bitStream = bitStringBuilder.ToString(); // 비트 스트림에서 시작 및 종료 마커를 찾는다. int startMarkerIndex = bitStream.IndexOf(startMarkerBitString); int endMarkerIndex = bitStream.IndexOf(endMarkerBitString); if(startMarkerIndex == -1 || endMarkerIndex == -1) { Console.WriteLine("시작 또는 종료 마커를 찾을 수 없습니다."); return; } int dataStart = startMarkerIndex + startMarkerBitString.Length; int dataEnd = endMarkerIndex; string dataBitStream = bitStream.Substring(dataStart, dataEnd - dataStart); // 파일 크기를 추출한다. (첫 32비트) if(dataBitStream.Length < 32) { Console.WriteLine("파일 크기 정보를 읽을 수 없습니다."); return; } string fileSizeString = dataBitStream.Substring(0, 32); dataBitStream = dataBitStream.Substring(32); // 파일 크기를 정수로 변환한다. int fileSize = Convert.ToInt32(fileSizeString, 2); // 결정할 수 없는 비트를 제거한다. dataBitStream = dataBitStream.Replace("?", ""); // 비트를 바이트로 변환한다. int byteCount = dataBitStream.Length / 8; byte[] dataByteArray = new byte[byteCount]; for(int i = 0; i < byteCount; i++) { string byteBitString = dataBitStream.Substring(i * 8, 8); dataByteArray[i] = Convert.ToByte(byteBitString, 2); } // 파일 크기에 따라 데이터를 자른다. if(dataByteArray.Length > fileSize) { byte[] tempByteArray = new byte[fileSize]; Array.Copy(dataByteArray, tempByteArray, fileSize); dataByteArray = tempByteArray; } // 복원된 파일을 저장한다. File.WriteAllBytes(targetFilePath, dataByteArray); Console.WriteLine("디코딩 완료 : " + targetFilePath); } #endregion } |
[Decoder 프로젝트] ▶ requirements.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
using System; using System.IO; using System.Linq; using NAudio.Wave; namespace ENCODER; /// <summary> /// 인코더 /// </summary> class Encoder { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main(argumentArray) /// <summary> /// 프로그램 시작하기 /// </summary> /// <param name="argumentArray">인자 배열</param> private static void Main(string[] argumentArray) { if(argumentArray.Length != 2) { Console.WriteLine("사용법 : encoder.exe source.zip target.wav"); return; } string sourceFilePath = argumentArray[0]; string targetFilePath = argumentArray[1]; // 소스 파일을 읽는다. byte[] sourceFileByteArray = File.ReadAllBytes(sourceFilePath); int sourceFileSize = sourceFileByteArray.Length; // 바이트를 비트로 변환한다. string dataBitString = string.Join(string.Empty, sourceFileByteArray.Select(sourceByte => Convert.ToString(sourceByte, 2).PadLeft(8, '0'))); // 파일 크기를 헤더에 추가한다. (32비트로 표현) string fileSizeBitString = Convert.ToString(sourceFileSize, 2).PadLeft(32, '0'); // 시작 및 종료 마커 문자열을 설정한다. string startMarkerString = "1111000011110000"; string endMarkerString = "0000111100001111"; // 전체 비트 스트림을 생성한다. string bitStreamString = startMarkerString + fileSizeBitString + dataBitString + endMarkerString; // 파라미터를 설정한다. int samplingFrequency = 44100; // 샘플링 주파수 double durationPerBit = 0.01; // 각 비트의 지속 시간 (초) int sampleCountPerBit = (int)(samplingFrequency * durationPerBit); int frequency0 = 1000; // '0'에 대한 주파수 int frequency1 = 2000; // '1'에 대한 주파수 // 신호를 생성한다. float[] signalArray = new float[bitStreamString.Length * sampleCountPerBit]; int bitStreamStringLength = bitStreamString.Length; for(int i = 0; i < bitStreamStringLength; i++) { char bitCharacter = bitStreamString[i]; int frequency = bitCharacter == '1' ? frequency1 : frequency0; for(int j = 0; j < sampleCountPerBit; j++) { double t = (double)j / samplingFrequency; signalArray[i * sampleCountPerBit + j] = (float)Math.Sin(2 * Math.PI * frequency * t); } } // 신호를 정규화한다. float maximumAmplitude = signalArray.Max(x => Math.Abs(x)); for(int i = 0; i < signalArray.Length; i++) { signalArray[i] = signalArray[i] / maximumAmplitude; } // WAV 파일로 저장한다. using(WaveFileWriter waveFileWriter = new WaveFileWriter(targetFilePath, new WaveFormat(samplingFrequency, 16, 1))) { waveFileWriter.WriteSamples(signalArray, 0, signalArray.Length); } Console.WriteLine("인코딩 완료 : " + targetFilePath); } #endregion } |
TestSolution.zip
■ ManagementObjectSearcher 클래스를 사용해 NVIDIA GPU 설치 여부를 구하는 방법을 보여준다. ▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
using System; using System.Management; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region NVIDIA GPU 설치 여부 구하기 - IsInstalledNvidiaGPU() /// <summary> /// NVIDIA GPU 설치 여부 구하기 /// </summary> /// <returns>NVIDIA GPU 설치 여부</returns> private static bool IsInstalledNvidiaGPU() { using ManagementObjectSearcher managementObjectSearcher = new("SELECT * FROM Win32_VideoController"); foreach(ManagementObject managementObject in managementObjectSearcher.Get()) { string name = managementObject["Name"] as string; if(!string.IsNullOrEmpty(name) && name.ToLower().Contains("nvidia")) { return true; } } return false; } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { bool isInstalledNvidiaGPU = IsInstalledNvidiaGPU(); Console.WriteLine(isInstalledNvidiaGPU ? "NVIDIA GPU가 설치되어 있습니다." : "NVIDIA GPU가 설치되어 있지 않습니다."); } #endregion } |
TestProject.zip
■ RuntimeInformation 클래스의 IsOSPlatform 정적 메소드를 사용해 윈도우즈 운영 체제가 아닌 경우 실행을 중단하는 방법을 보여준다. ▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using System; using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Console.WriteLine("이 프로그램은 Windows에서만 실행할 수 있습니다."); return; } } #endregion } |
TestProject.zip
■ rank_bm25 패키지를 설치하는 방법을 보여준다. 1. 명령 프롬프트를 실행한다. 2. 명령 프롬프트에서 아래 명령을 실행한다. ▶ 실행 명령
1 2 3 |
pip install rank_bm25 |
■ lark 패키지를 설치하는 방법을 보여준다. 1. 명령 프롬프트를 실행한다. 2. 명령 프롬프트에서 아래 명령을 실행한다. ▶ 실행 명령
1 2 3 |
pip install lark |
■ HttpClient 클래스를 사용해 Ollama 연동 파이썬 LLM 서버와 통신하는 방법을 보여준다. ▶ AdditionalKeywordArgument.cs
1 2 3 4 5 6 7 8 9 10 |
namespace TestProject; /// <summary> /// 부가적 키워드 인자 /// </summary> public class AdditionalKeywordArgument { } |
▶ AIMessageChunk.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// AI 메시지 청크 /// </summary> public class AIMessageChunk { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 컨텐트 - Content /// <summary> /// 컨텐트 /// </summary> [JsonProperty("content")] public string Content { get; set; } #endregion #region 부가적 키워드 인자 - AdditionalKeywordArgument /// <summary> /// 부가적 키워드 인자 /// </summary> [JsonProperty("additional_kwargs")] public AdditionalKeywordArgument AdditionalKeywordArgument { get; set; } #endregion #region 응답 메타 데이터 - ResponseMetadata /// <summary> /// 응답 메타 데이터 /// </summary> [JsonProperty("response_metadata")] public ResponseMetadata ResponseMetadata { get; set; } #endregion #region 타입 - Type /// <summary> /// 타입 /// </summary> [JsonProperty("type")] public string Type { get; set; } #endregion #region 명칭 - Name /// <summary> /// 명칭 /// </summary> [JsonProperty("name")] public string Name { get; set; } #endregion #region ID - ID /// <summary> /// ID /// </summary> [JsonProperty("id")] public string ID { get; set; } #endregion #region 예제 여부 - Example /// <summary> /// 예제 여부 /// </summary> [JsonProperty("example")] public bool Example { get; set; } #endregion #region 도구 호출 리스트 - ToolCallList /// <summary> /// 도구 호출 리스트 /// </summary> [JsonProperty("tool_calls")] public ToolCallList ToolCallList { get; set; } #endregion #region 무효 도구 호출 리스트 - InvalidToolCallList /// <summary> /// 무효 도구 호출 리스트 /// </summary> [JsonProperty("invalid_tool_calls")] public InvalidToolCallList InvalidToolCallList { get; set; } #endregion #region 사용 메타 데이터 - UsageMetadata /// <summary> /// 사용 메타 데이터 /// </summary> [JsonProperty("usage_metadata")] public UsageMetadata UsageMetadata { get; set; } #endregion #region 도구 호출 청크 리스트 - ToolCallChunkList /// <summary> /// 도구 호출 청크 리스트 /// </summary> [JsonProperty("tool_call_chunks")] public ToolCallChunkList ToolCallChunkList { get; set; } #endregion } |
▶ InvalidToolCallList.cs
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Collections.Generic; namespace TestProject; /// <summary> /// 무효 도구 호출 리스트 /// </summary> public class InvalidToolCallList : List<object> { } |
▶
■ Marshal 클래스의 SizeOf 정적 메소드를 사용해 특정 타입의 크기를 구하는 방법을 보여준다. ▶ DataStruct.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// 데이터 구조체 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct DataStruct { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 정수 값 /// </summary> public int IntegerValue; /// <summary> /// 배정도 실수 값 /// </summary> public double DoubleValue; /// <summary> /// 문자 값 /// </summary> public char CharacterValue; #endregion } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System.Runtime.InteropServices; using System; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> static void Main() { int size = Marshal.SizeOf<DataStruct>(); Console.WriteLine($"DataStruct 크기 : {size} 바이트"); } #endregion } |
TestProject.zip
■ WPF 앱에서 배경 애니메이션과 함께 네이버 HyperCLOVA X와 통신하는 방법을 보여준다. ▶ AIFilter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// AI 필터 /// </summary> public class AIFilter { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 그룹명 - GroupName /// <summary> /// 그룹명 /// </summary> [JsonProperty("groupName")] public string GroupName { get; set; } #endregion #region 명칭 - Name /// <summary> /// 명칭 /// </summary> [JsonProperty("name")] public string Name { get; set; } #endregion #region 점수 - Score /// <summary> /// 점수 /// </summary> [JsonProperty("score")] public string Score { get; set; } #endregion #region 결과 - Result /// <summary> /// 결과 /// </summary> [JsonProperty("result")] public string Result { get; set; } #endregion } |
▶ Message.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// 메시지 /// </summary> public class Message { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 역할 - Role /// <summary> /// 역할 /// </summary> [JsonProperty("role")] public string Role { get; set; } #endregion #region 내용 - Content /// <summary> /// 내용 /// </summary> [JsonProperty("content")] public string Content { get; set; } #endregion } |
▶ RequestMessage.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
using System.Collections.Generic; using Newtonsoft.Json; namespace TestProject; /// <summary> /// 요청 메시지 /// </summary> public class RequestMessage { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 메시지 리스트 - MessageList /// <summary> /// 메시지 리스트 /// </summary> [JsonProperty("messages")] public List<Message> MessageList { get; set; } #endregion #region Top P - TopP /// <summary> /// TopP /// </summary> [JsonProperty("topP")] public double TopP { get; set; } #endregion #region Top K - TopK /// <summary> /// TopK /// </summary> [JsonProperty("topK")] public int TopK { get; set; } #endregion #region 최대 토큰 카운트 - MaximumTokenCount /// <summary> /// 최대 토큰 카운트 /// </summary> [JsonProperty("maxTokens")] public int MaximumTokenCount { get; set; } #endregion #region 온도 - Temperature /// <summary> /// 온도 /// </summary> [JsonProperty("temperature")] public double Temperature { get; set; } #endregion #region 반복 패널티 - RepeatPenalty /// <summary> /// 반복 패널티 /// </summary> [JsonProperty("repeatPenalty")] public double RepeatPenalty { get; set; } #endregion #region Stop Before - StopBefore /// <summary> /// Stop Before /// </summary> [JsonProperty("stopBefore")] public List<string> StopBefore { get; set; } #endregion #region AI 필터 포함 여부 - IncludeAIFilters /// <summary> /// AI 필터 포함 여부 /// </summary> [JsonProperty("includeAiFilters")] public bool IncludeAIFilters { get; set; } #endregion #region 시드 - Seed /// <summary> /// 시드 /// </summary> [JsonProperty("seed")] public int Seed { get; set; } #endregion } |
▶
■ HttpClient 클래스를 사용해 네이버 HyperCLOVA X와 통신하는 방법을 보여준다. (IAsyncEnumerable<T> 객체) ▶ AIFilter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// AI 필터 /// </summary> public class AIFilter { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 그룹명 - GroupName /// <summary> /// 그룹명 /// </summary> [JsonProperty("groupName")] public string GroupName { get; set; } #endregion #region 명칭 - Name /// <summary> /// 명칭 /// </summary> [JsonProperty("name")] public string Name { get; set; } #endregion #region 점수 - Score /// <summary> /// 점수 /// </summary> [JsonProperty("score")] public string Score { get; set; } #endregion #region 결과 - Result /// <summary> /// 결과 /// </summary> [JsonProperty("result")] public string Result { get; set; } #endregion } |
▶ Message.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// 메시지 /// </summary> public class Message { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 역할 - Role /// <summary> /// 역할 /// </summary> [JsonProperty("role")] public string Role { get; set; } #endregion #region 내용 - Content /// <summary> /// 내용 /// </summary> [JsonProperty("content")] public string Content { get; set; } #endregion } |
▶ RequestMessage.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// 요청 메시지 /// </summary> public class RequestMessage { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 메시지 리스트 - MessageList /// <summary> /// 메시지 리스트 /// </summary> [JsonProperty("messages")] public List<Message> MessageList { get; set; } #endregion #region Top P - TopP /// <summary> /// TopP /// </summary> [JsonProperty("topP")] public double TopP { get; set; } #endregion #region Top K - TopK /// <summary> /// TopK /// </summary> [JsonProperty("topK")] public int TopK { get; set; } #endregion #region 최대 토큰 카운트 - MaximumTokenCount /// <summary> /// 최대 토큰 카운트 /// </summary> [JsonProperty("maxTokens")] public int MaximumTokenCount { get; set; } #endregion #region 온도 - Temperature /// <summary> /// 온도 /// </summary> [JsonProperty("temperature")] public double Temperature { get; set; } #endregion #region 반복 패널티 - RepeatPenalty /// <summary> /// 반복 패널티 /// </summary> [JsonProperty("repeatPenalty")] public double RepeatPenalty { get; set; } #endregion #region Stop Before - StopBefore /// <summary> /// Stop Before /// </summary> [JsonProperty("stopBefore")] public List<string> StopBefore { get; set; } #endregion #region AI 필터 포함 여부 - IncludeAIFilters /// <summary> /// AI 필터 포함 여부 /// </summary> [JsonProperty("includeAiFilters")] public bool IncludeAIFilters { get; set; } #endregion #region 시드 - Seed /// <summary> /// 시드 /// </summary> [JsonProperty("seed")] public int Seed { get; set; } #endregion } |
▶
■ ManagementObjectSearcher 클래스를 사용해 시스템 정보를 구하는 방법을 보여준다. ▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#pragma warning disable CA1416 using System.Management; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { try { ManagementObjectSearcher searcher; // PC 모델 및 제조업체 정보 searcher = new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem"); foreach(ManagementObject mo in searcher.Get()) { Console.WriteLine($"PC 모델 : {mo["Model" ]}"); Console.WriteLine($"제조업체 : {mo["Manufacturer"]}"); } // 제조번호(시리얼 넘버) 정보 searcher = new ManagementObjectSearcher("SELECT * FROM Win32_BIOS"); foreach(ManagementObject mo in searcher.Get()) { Console.WriteLine($"제조번호(시리얼 넘버) : {mo["SerialNumber"]}"); } // CPU 정보 searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); foreach(ManagementObject mo in searcher.Get()) { Console.WriteLine($"CPU : {mo["Name"]}"); } // 메인보드 정보 searcher = new ManagementObjectSearcher("SELECT * FROM Win32_BaseBoard"); foreach(ManagementObject mo in searcher.Get()) { Console.WriteLine($"메인보드 제조사 : {mo["Manufacturer"]}"); Console.WriteLine($"메인보드 제품 ID : {mo["Product" ]}"); Console.WriteLine($"메인보드 시리얼 번호 : {mo["SerialNumber"]}"); } // 메모리 용량 정보 searcher = new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem"); foreach(ManagementObject mo in searcher.Get()) { ulong totalPhysicalMemory = Convert.ToUInt64(mo["TotalPhysicalMemory"]); Console.WriteLine($"메모리 용량 : {(totalPhysicalMemory / (1024 * 1024 * 1024))} GB"); } } catch (Exception exception) { Console.WriteLine("오류 발생 : " + exception.Message); } Console.WriteLine("아무 키나 누르면 종료됩니다..."); Console.ReadKey(false); } #endregion } |
TestProject.zip
■ Typeface 클래스에서 Segoe UI Emoji 폰트를 사용해 이모지 문자를 나열하는 방법을 보여준다. ▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="TestProject" Height="600" Width="800" FontFamily="나눔소딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ListBox Name="listBox" Grid.Row="0" BorderThickness="1" BorderBrush="DarkGray" FontFamily="Segoe UI Emoji" FontSize="24"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal" Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> <TextBlock Name="textBlock" Grid.Row="1" Margin="0 10 0 0" /> </Grid> </Window> |
▶ MainWindow.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace TestProject; /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); Typeface emojiTypeface = new Typeface ( new FontFamily("Segoe UI Emoji"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal ); List<(int, int)> emojiRangeList = new List<(int, int)> { (0x1f300, 0x1f5ff), // Miscellaneous Symbols and Pictographs (0x1f600, 0x1f64f), // Emoticons (0x1f680, 0x1f6ff), // Transport and Map Symbols (0x1f900, 0x1f9ff), // Supplemental Symbols and Pictographs (0x1fa70, 0x1faff), // Symbols and Pictographs Extended-A (0x2600 , 0x26ff ), // Miscellaneous Symbols (0x2700 , 0x27bf ) // Dingbats }; foreach((int start, int end) in emojiRangeList) { for(int i = start; i <= end; i++) { string emojiString = char.ConvertFromUtf32(i); if(HasGlyph(emojiTypeface, emojiString)) { this.listBox.Items.Add(emojiString); } } } this.listBox.SelectionChanged += listBox_SelectionChanged; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 리스트 박스 선택 변경시 처리하기 - listBox_SelectionChanged(sender, e) /// <summary> /// 리스트 박스 선택 변경시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if(this.listBox.SelectedItem != null) { string emojiString = this.listBox.SelectedItem.ToString(); int unicode = char.ConvertToUtf32(emojiString, 0); this.textBlock.Text = $"유니코드 : U+{unicode:X4}"; } } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 글리프 소유 여부 구하기 - HasGlyph(typeface, source) /// <summary> /// 글리프 소유 여부 구하기 /// </summary> /// <param name="typeface">타입 페이스</param> /// <param name="source">소스 문자열</param> /// <returns>글리프 소유 여부</returns> private bool HasGlyph(Typeface typeface, string source) { ushort glyphIndex; bool resultToGetGlyphTypeface = typeface.TryGetGlyphTypeface(out GlyphTypeface glyphTypeface); bool resultToGetGlyphIndex = glyphTypeface.CharacterToGlyphMap.TryGetValue(char.ConvertToUtf32(source, 0), out glyphIndex); return resultToGetGlyphTypeface && resultToGetGlyphIndex && glyphIndex != 0; } #endregion } |
TestProject.zip
■ Segoe UI Emoji 폰트에서 이모지 문자 여부를 구하는 방법을 보여준다. ▶ Segoe UI Emoji 폰트에서 이모지 문자 여부 구하기 예제 (C#)
■ Typeface 클래스를 사용해 이모지 타입 페이스 객체를 만드는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Windows; using System.Windows.Media; Typeface emojiTypeface = new Typeface ( new FontFamily("Segoe UI Emoji"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal ); |
■ char 구조체의 ConvertToUtf32 정적 메소드를 사용해 이모지 문자에서 UTF-32 문자 코드를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
string smileString = char.ConvertFromUtf32(0x1f600); // 반환값: "😀" (웃는 얼굴 이모지) string dragonString = char.ConvertFromUtf32(0x1f409); // 반환값: "🐉" (용 이모지) int smileCode = char.ConvertToUtf32(smileString , 0); int dragonCode = char.ConvertToUtf32(dragonString, 0); Console.WriteLine($"0x{smileCode :x}"); Console.WriteLine($"0x{dragonCode:x}"); /* 0x1f600 0x1f409 */ |
■ char 구조체의 ConvertFromUtf32 정적 메소드를 사용해 이모지 문자를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 |
string smileString = char.ConvertFromUtf32(0x1f600); // 반환값: "😀" (웃는 얼굴 이모지) string dragonString = char.ConvertFromUtf32(0x1f409); // 반환값: "🐉" (용 이모지) |