첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

▶ KoreanStringExtension.cs

using System.Collections.Generic;
using System.Text;

namespace TestProject
{
    /// <summary>
    /// 한국어 문자열 확장
    /// </summary>
    public static class KoreanStringExtension
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Interface
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 한국어 문자열 인터페이스 - IKoreanString

        /// <summary>
        /// 한국어 문자열 인터페이스
        /// </summary>
        public interface IKoreanString
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Method

            #region 한국어 매칭 문자열 구하기 - GetKoreanMatchingString(source, keyword)

            /// <summary>
            /// 한국어 매칭 문자열 구하기
            /// </summary>
            /// <param name="source">소스 문자열</param>
            /// <param name="keyword">키워드</param>
            /// <returns>한국어 매칭 문자열</returns>
            string GetKoreanMatchingString(string source, string keyword);

            #endregion
            #region 한국어 매칭 문자열 인덱스 구하기 - GetKoreanMatchingStringIndex(source, keyword)

            /// <summary>
            /// 한국어 매칭 문자열 인덱스 구하기
            /// </summary>
            /// <param name="source">소스 문자열</param>
            /// <param name="keyword">키워드</param>
            /// <returns>한국어 매칭 문자열 인덱스</returns>
            int GetKoreanMatchingStringIndex(string source, string keyword);

            #endregion
            #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword)

            /// <summary>
            /// 한국어 동일 여부 구하기
            /// </summary>
            /// <param name="source">소스 문자</param>
            /// <param name="keyword">키워드 문자</param>
            /// <returns>한국어 동일 여부</returns>
            bool EqualKorean(char source, char keyword);

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Class
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 기정의 문자열 매칭자 - PredefinedStringMatcher

        /// <summary>
        /// 기정의 문자열 매칭자
        /// </summary>
        public static class PredefinedStringMatcher
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Field
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Field

            #region Field

            /// <summary>
            /// 디폴트
            /// </summary>
            public static GetKoreanMatchingStringDelegate Default = GetMatchingString;

            /// <summary>
            /// 자모
            /// </summary>
            public static GetKoreanMatchingStringDelegate Jamo = GetMatchingString;

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Private

            #region 매칭 문자열 구하기 - GetMatchingString(source, keyword)

            /// <summary>
            /// 매칭 문자열 구하기
            /// </summary>
            /// <param name="source">소스 문자열</param>
            /// <param name="keyword">키워드</param>
            /// <returns>매칭 문자열</returns>
            private static string GetMatchingString(string source, string keyword)
            {
                if(source.GetKoreanIndex(keyword) == -1)
                {
                    return null;
                }
                else
                {
                    return source.Substring(source.GetKoreanIndex(keyword), keyword.Length);
                }
            }

            #endregion
        }

        #endregion
        #region 기정의 문자열 인덱스 발견자 - PredefinedStringIndexFinder

        /// <summary>
        /// 기정의 문자열 인덱스 발견자
        /// </summary>
        public static class PredefinedStringIndexFinder
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Field
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Public

            #region Field

            /// <summary>
            /// 디폴트
            /// </summary>
            public static GetKoreanMatchingStringIndexDelegate Default = GetMatchingStringIndex;

            /// <summary>
            /// 자모
            /// </summary>
            public static GetKoreanMatchingStringIndexDelegate Jamo = GetMatchingStringIndex;

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Private

            #region 매칭 문자열 인덱스 구하기 - GetMatchingStringIndex(source, keyword)

            /// <summary>
            /// 매칭 문자열 인덱스 구하기
            /// </summary>
            /// <param name="source">소스 문자열</param>
            /// <param name="keyword">키워드</param>
            /// <returns>매칭 문자열 인덱스</returns>
            private static int GetMatchingStringIndex(string source, string keyword)
            {
                if(keyword.Length > source.Length)
                {
                    return -1;
                }

                if(keyword.Length == 0)
                {
                    return 0;
                }

                int maximum = source.Length - keyword.Length;

                char firstKeyword = keyword[0];

                for(int i = 0; i <= maximum; i++)
                {
                    if(source[i].EqualKorean(firstKeyword) == false)
                    {
                        while(++i <= maximum && source[i].EqualKorean(firstKeyword) == false);
                    }

                    if(i <= maximum)
                    {
                        int startIndex = i + 1;
                        int endIndex   = startIndex + keyword.Length - 1;

                        for(int keywordIndex = 1; startIndex < endIndex; keywordIndex++, startIndex++)
                        {
                            if(source[startIndex].EqualKorean(keyword[keywordIndex]))
                            {
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }

                        if(startIndex == endIndex)
                        {
                            return i;
                        }
                    }
                }

                return -1;
            }

            #endregion
        }

        #endregion
        #region 기정의 문자 비교자 - PredefinedCharComparator

        /// <summary>
        /// 기정의 문자 비교자
        /// </summary>
        public class PredefinedCharComparator
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Field
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Public

            #region Field

            /// <summary>
            /// 디폴트
            /// </summary>
            public static CompareCharacterDelegate Default = CompareCharacter;

            /// <summary>
            /// 자모
            /// </summary>
            public static CompareCharacterDelegate Jamo = CompareCharacter;

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Private

            #region 문자 비교하기 - CompareCharacter(source, keyword)

            /// <summary>
            /// 문자 비교하기
            /// </summary>
            /// <param name="source">소스 문자</param>
            /// <param name="keyword">키워드</param>
            /// <returns>문자 비교 결과</returns>
            private static bool CompareCharacter(char source, char keyword)
            {
                bool result = false;

                int jamoLevel = keyword.GetJamoLevel();

                switch(jamoLevel)
                {
                    case 1  : result = source.MatchLevel1Jamo(keyword); break;
                    case 2  : result = source.MatchLevel2Jamo(keyword); break;
                    default : result = (source == keyword);             break;
                }

                return result;
            }

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 한국어 매칭 문자열 구하기 대리자 - GetKoreanMatchingStringDelegate(source, keyword)

        /// <summary>
        /// 한국어 매칭 문자열 구하기 대리자
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <returns>한국어 매칭 문자열</returns>
        public delegate string GetKoreanMatchingStringDelegate(string source, string keyword);

        #endregion
        #region 한국어 매칭 문자열 인덱스 구하기 대리자 - GetKoreanMatchingStringIndexDelegate(source, keyword)

        /// <summary>
        /// 한국어 매칭 문자열 인덱스 구하기 대리자
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <returns>한국어 매칭 문자열 인덱스</returns>
        public delegate int GetKoreanMatchingStringIndexDelegate(string source, string keyword);

        #endregion
        #region 문자 비교하기 대리자 - CompareCharacterDelegate(source, keyword)

        /// <summary>
        /// 문자 비교하기 대리자
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <param name="keyword">키워드 문자</param>
        /// <returns>문자 비교 결과</returns>
        public delegate bool CompareCharacterDelegate(char source, char keyword);

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Staitc
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 초성 딕셔너리
        /// </summary>
        /// <remarks>한글 호환 자모 영역에 있는 글자들을 한글 자모 영역의 초성으로 맵핑한다.</remarks>
        private static Dictionary<char, char> _chosungDictionary = new Dictionary<char, char>()
        {
            {'\x3131', '\x1100'}, // ㄱ
            {'\x3132', '\x1101'}, // ㄲ
            {'\x3134', '\x1102'}, // ㄴ
            {'\x3137', '\x1103'}, // ㄷ
            {'\x3138', '\x1104'}, // ㄸ
            {'\x3139', '\x1105'}, // ㄹ
            {'\x3141', '\x1106'}, // ㅁ
            {'\x3142', '\x1107'}, // ㅂ
            {'\x3143', '\x1108'}, // ㅃ
            {'\x3145', '\x1109'}, // ㅅ
            {'\x3146', '\x110A'}, // ㅆ
            {'\x3147', '\x110B'}, // ㅇ
            {'\x3148', '\x110C'}, // ㅈ
            {'\x3149', '\x110D'}, // ㅉ
            {'\x314A', '\x110E'}, // ㅊ
            {'\x314B', '\x110F'}, // ㅋ
            {'\x314C', '\x1110'}, // ㅌ
            {'\x314D', '\x1111'}, // ㅍ
            {'\x314E', '\x1112'}  // ㅎ
        };

        /// <summary>
        /// 역 초성 딕셔너리
        /// </summary>
        /// <remarks>한글 자모 영역의 초성을 한글 호환 자모 영역에 있는 글자들로 맵핑한다.</remarks>
        private static Dictionary<char, char> _reverseChosungDictionary = new Dictionary<char, char>()
        {
            { '\x1100' , '\x3131' }, // ㄱ
            { '\x1101' , '\x3132' }, // ㄲ
            { '\x1102' , '\x3134' }, // ㄴ
            { '\x1103' , '\x3137' }, // ㄷ
            { '\x1104' , '\x3138' }, // ㄸ
            { '\x1105' , '\x3139' }, // ㄹ
            { '\x1106' , '\x3141' }, // ㅁ
            { '\x1107' , '\x3142' }, // ㅂ
            { '\x1108' , '\x3143' }, // ㅃ
            { '\x1109' , '\x3145' }, // ㅅ
            { '\x110A' , '\x3146' }, // ㅆ
            { '\x110B' , '\x3147' }, // ㅇ
            { '\x110C' , '\x3148' }, // ㅈ
            { '\x110D' , '\x3149' }, // ㅉ
            { '\x110E' , '\x314A' }, // ㅊ
            { '\x110F' , '\x314B' }, // ㅋ
            { '\x1110' , '\x314C' }, // ㅌ
            { '\x1111' , '\x314D' }, // ㅍ
            { '\x1112' , '\x314E' }  // ㅎ
        };

        /// <summary>
        /// 역 중성 딕셔너리
        /// </summary>
        /// <remarks>한글 자모 영역의 중성을 한글 호환 자모 영역에 있는 글자들로 맵핑한다.</remarks>
        private static Dictionary<char, char> _reverseJoongsungDictionary = new Dictionary<char, char>()
        {
            {'\x1161','\x314F'}, // ㅏ
            {'\x1162','\x3150'}, // ㅐ
            {'\x1163','\x3151'}, // ㅑ
            {'\x1164','\x3152'}, // ㅒ
            {'\x1165','\x3153'}, // ㅓ
            {'\x1166','\x3154'}, // ㅔ
            {'\x1167','\x3155'}, // ㅕ
            {'\x1168','\x3156'}, // ㅖ
            {'\x1169','\x3157'}, // ㅗ
            {'\x116A','\x3158'}, // ㅘ
            {'\x116B','\x3159'}, // ㅙ
            {'\x116C','\x315A'}, // ㅚ
            {'\x116D','\x315B'}, // ㅛ
            {'\x116E','\x315C'}, // ㅜ
            {'\x116F','\x315D'}, // ㅝ
            {'\x1170','\x315E'}, // ㅞ
            {'\x1171','\x315F'}, // ㅟ
            {'\x1172','\x3160'}, // ㅠ
            {'\x1173','\x3161'}, // ㅡ
            {'\x1174','\x3162'}, // ㅢ
            {'\x1175','\x3163'}, // ㅣ
        };

        /// <summary>
        /// 역 종성 딕셔너리
        /// </summary>
        /// <remarks>한글 자모 영역의 종성을 한글 호환 자모 영역에 있는 글자들로 맵핑한다.</remarks>
        private static Dictionary<char, char> _reverseJongsungDictionary = new Dictionary<char, char>()
        {
            {'\x11A8','\x3131'}, // ㄱ
            {'\x11A9','\x3132'}, // ㄲ
            {'\x11AA','\x3133'}, // ㄱㅅ
            {'\x11AB','\x3134'}, // ㄴ
            {'\x11AC','\x3135'}, // ㄴㅈ
            {'\x11AD','\x3136'}, // ㄴㅎ
            {'\x11AE','\x3137'}, // ㄷ
            {'\x11AF','\x3139'}, // ㄹ
 
            {'\x11B0','\x313A'}, // ㄹㄱ 
            {'\x11B1','\x313B'}, // ㄹㅁ
            {'\x11B2','\x313C'}, // ㄹㅂ
            {'\x11B3','\x313D'}, // ㄹㅅ
            {'\x11B4','\x313E'}, // ㄹㅌ
            {'\x11B5','\x313F'}, // ㄹㅍ
            {'\x11B6','\x3140'}, // ㄹㅎ
            {'\x11B7','\x3141'}, // ㅁ
            {'\x11B8','\x3142'}, // ㅂ
            {'\x11B9','\x3144'}, // ㅂㅅ
            {'\x11BA','\x3145'}, // ㅅ
            {'\x11BB','\x3146'}, // ㅆ
            {'\x11BC','\x3147'}, // ㅇ
            {'\x11BD','\x3148'}, // ㅈ 
            {'\x11BE','\x314A'}, // ㅊ
            {'\x11BF','\x314B'}, // ㅋ
 
            {'\x11C0','\x31C'}, // ㅌ
            {'\x11C1','\x31D'}, // ㅍ
            {'\x11C2','\x31E'}, // ㅎ
        };

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 한글 음절 시작
        /// </summary>
        private const char HANGUL_SYLLABLE_START = '\xAC00';

        /// <summary>
        /// 한글 음절 종료
        /// </summary>
        private const char HANGUL_SYLLABLE_END = '\xD79F';

        /// <summary>
        /// 한글 자모 시작
        /// </summary>
        private const char HANGUL_JAMO_START = '\x1100';

        /// <summary>
        /// 한글 자모 종료
        /// </summary>
        private const char HANGUL_JAMO_END = '\x11FF';

        /// <summary>
        /// 한글 자모 모음 시작
        /// </summary>
        private const char HANGUL_JAMO_MOUM_START = '\x1161';

        /// <summary>
        /// 한글 자모 종성 시작
        /// </summary>
        private const char HANGUL_JAMO_JONGSUNG_START = '\x11A8';

        /// <summary>
        /// 한글 문자 시작
        /// </summary>
        private const char HANGUL_LETTER_START = '\x3130';

        /// <summary>
        /// 한글 문자 종료
        /// </summary>
        private const char HANGUL_LETTER_END = '\x318F';

        /// <summary>
        /// 종성 간격
        /// </summary>
        private const char CHOSUNG_INTERVAL = (char)(28 * 21);

        /// <summary>
        /// 중성 간격
        /// </summary>
        private const char JOONGSUNG_INTERVAL = (char)28;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Staitc
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 조사 추가하기 - AppendJosa(this string source, string josaAfterJongsung, string josaAfterNonJongsung)

        /// <summary>
        /// 조사 추가하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="josaAfterJongsung">받침과 함께 끝나는 단어 뒤에 붙을 조사</param>
        /// <param name="josaAfterNonJongsung">받침 없이 끝나는 단어 뒤에 붙을 조사</param>
        /// <returns>조사 추가 문자열</returns>
        public static string AppendJosa(this string source, string josaAfterJongsung, string josaAfterNonJongsung)
        {
            if(source.Trim().Length == 0)
            {
                return source;
            }

            char lastCharacter = source[source.Length - 1];

            if(lastCharacter.IsInHangulSyllableRange())
            {
                return (lastCharacter.IsCharacterLevel3()) ? source + josaAfterJongsung : source + josaAfterNonJongsung;
            }

            return source;
        }

        #endregion
        #region 조사 추가하기 - AppendJosa(source, josaType)

        /// <summary>
        /// 조사 추가하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="josaType">조사 타입</param>
        /// <remarks>
        /// EN  : 은   또는 는
        /// ER  : 을   또는 를
        /// WG  : 과   또는 와
        /// YDD : 이다 또는 다
        /// YG  : 이   또는 가
        /// </remarks>
        /// <returns>조사 추가 문자열</returns>
        public static string AppendJosa(this string source, JosaType josaType)
        {
            switch(josaType)
            {
                case JosaType.EN  : return source.AppendJosa("은"  , "는");
                case JosaType.ER  : return source.AppendJosa("을"  , "를");
                case JosaType.WG  : return source.AppendJosa("과"  , "와");
                case JosaType.YDD : return source.AppendJosa("이다", "다");
                case JosaType.YG  : return source.AppendJosa("이"  , "가");
                case JosaType.ERR : return source.AppendJosa("으로", "로");
                default           : return source;
            }
        }

        #endregion

        #region 초성 추출하기 - ExtractChosung(source)

        /// <summary>
        /// 초성 추출하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <remarks>
        /// "한글초성".ExtractChosung()   -> "ㅎㄱㅊㅅ"
        /// "Korean초성".ExtractChosung() -> "Koreanㅊㅅ"
        /// </remarks>
        /// <returns>초성 추출 문자열</returns>
        public static string ExtractChosung(this string source)
        {
            if(source.Trim().Length == 0)
            {
                return "";
            }

            StringBuilder stringBuilder = new StringBuilder();

            for(int i = 0; i < source.Length; i++)
            {
                if(source[i].IsInHangulSyllableRange())
                {
                    char chosung = (char)((source[i] - HANGUL_SYLLABLE_START) / CHOSUNG_INTERVAL + HANGUL_JAMO_START);

                    stringBuilder.Append(GetChosungLetter(chosung));
                }
                else
                {
                    stringBuilder.Append(source[i]);
                }
            }

            return stringBuilder.ToString();
        }

        #endregion

        #region 한국어 매칭 문자열 구하기 - GetKoreanMatchingString(source, keyword, getKoreanMatchingStringDelegate)

        /// <summary>
        /// 한국어 매칭 문자열 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="getKoreanMatchingStringDelegate">매칭 문자열 구하기 대리자</param>
        /// <returns>한국어 매칭 문자열</returns>
        public static string GetKoreanMatchingString(this string source, string keyword, GetKoreanMatchingStringDelegate getKoreanMatchingStringDelegate)
        {
            return getKoreanMatchingStringDelegate(source, keyword);
        }

        #endregion
        #region 한국어 매칭 문자열 구하기 - GetKoreanMatchingString(source, keyword)

        /// <summary>
        /// 한국어 매칭 문자열 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <remarks>
        /// "한글초성".Matches("ㅊㅅ") -> "초성"
        /// "한글초성".Matches("초서") -> "초성"
        /// </remarks>
        /// <returns>한국어 매칭 문자열</returns>
        public static string GetKoreanMatchingString(this string source, string keyword)
        {
            return source.GetKoreanMatchingString(keyword, PredefinedStringMatcher.Default);
        }

        #endregion
        #region 한국어 매칭 문자열 구하기 - GetKoreanMatchingString(source, keyword, koreanString)

        /// <summary>
        /// 한국어 매칭 문자열 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="koreanString">한국어 문자열 인터페이스</param>
        /// <returns>한국어 매칭 문자열</returns>
        public static string GetKoreanMatchingString(this string source, string keyword, IKoreanString koreanString)
        {
            return koreanString.GetKoreanMatchingString(source, keyword);
        }

        #endregion

        #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword, getKoreanMatchingStringIndexDelegate)

        /// <summary>
        /// 한국어 동일 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="getKoreanMatchingStringIndexDelegate">한국어 매칭 문자열 인덱스 구하기 대리자</param>
        /// <returns>한국어 동일 여부</returns>
        public static bool EqualKorean(this string source, string keyword, GetKoreanMatchingStringIndexDelegate getKoreanMatchingStringIndexDelegate)
        {
            return (source.Length == keyword.Length) && (getKoreanMatchingStringIndexDelegate(source, keyword) == 0);
        }

        #endregion
        #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword)

        /// <summary>
        /// 한국어 동일 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <remarks>
        /// "한글초성".EqualKorean("ㅊㅅ")     -> false
        /// "한글초성".EqualKorean("ㅎㄱㅊㅅ") -> true
        /// "한글초성".EqualKorean("하글ㅊㅅ") -> true
        /// </remarks>
        /// <returns>한국어 동일 여부</returns>
        public static bool EqualKorean(this string source, string keyword)
        {
            return source.EqualKorean(keyword, PredefinedStringIndexFinder.Default);
        }

        #endregion
        #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword, koreanString)

        /// <summary>
        /// 한국어 동일 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="koreanString">한국어 문자열 인터페이스</param>
        /// <returns>한국어 동일 여부</returns>
        public static bool EqualKorean(this string source, string keyword, IKoreanString koreanString)
        {
            return (source.Length == keyword.Length) && (koreanString.GetKoreanMatchingStringIndex(source, keyword) == 0);
        }

        #endregion

        #region 한국어 포함 여부 구하기 - ContainKorean(source, keyword, getKoreanMatchingStringIndexDelegate)

        /// <summary>
        /// 한국어 포함 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="getKoreanMatchingStringIndexDelegate">한국어 매칭 문자열 인덱스 구하기 대리자</param>
        /// <returns>한국어 포함 여부</returns>
        public static bool ContainKorean(this string source, string keyword, GetKoreanMatchingStringIndexDelegate getKoreanMatchingStringIndexDelegate)
        {
            return (getKoreanMatchingStringIndexDelegate(source, keyword) != -1);
        }

        #endregion
        #region 한국어 포함 여부 구하기 - ContainKorean(source, keyword)

        /// <summary>
        /// 한국어 포함 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <remarks>"한글초성".ContainKorean("ㅊㅅ") -> true</remarks>
        /// <returns>한국어 포함 여부</returns>
        public static bool ContainKorean(this string source, string keyword)
        {
            return source.ContainKorean(keyword, PredefinedStringIndexFinder.Default);
        }

        #endregion
        #region 한국어 포함 여부 구하기 - ContainKorean(source, keyword, koreanString)

        /// <summary>
        /// 한국어 포함 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="koreanString">한국어 문자열 인터페이스</param>
        /// <returns>한국어 포함 여부</returns>
        public static bool ContainKorean(this string source, string keyword, IKoreanString koreanString)
        {
            return (koreanString.GetKoreanMatchingStringIndex(source, keyword) != -1);
        }

        #endregion

        #region 한국어 인덱스 구하기 - GetKoreanIndex(source, keyword, getKoreanMatchingStringIndexDelegate)

        /// <summary>
        /// 한국어 인덱스 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="getKoreanMatchingStringIndexDelegate">한국어 매칭 문자열 인덱스 구하기 대리자</param>
        /// <returns>한국어 인덱스</returns>
        public static int GetKoreanIndex(this string source, string keyword, GetKoreanMatchingStringIndexDelegate getKoreanMatchingStringIndexDelegate)
        {
            return getKoreanMatchingStringIndexDelegate(source, keyword);
        }

        #endregion
        #region 한국어 인덱스 구하기 - GetKoreanIndex(source, keyword)

        /// <summary>
        /// 한국어 인덱스 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <remarks>"한글초성".GetKoreanIndex("ㅊㅅ") -> 2</remarks>
        /// <returns>한국어 인덱스</returns>
        public static int GetKoreanIndex(this string source, string keyword)
        {
            return source.GetKoreanIndex(keyword, PredefinedStringIndexFinder.Default);
        }

        #endregion
        #region 한국어 인덱스 구하기 - GetKoreanIndex(source, keyword, koreanString)

        /// <summary>
        /// 한국어 인덱스 구하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="keyword">키워드</param>
        /// <param name="koreanString">한국어 문자열 인터페이스</param>
        /// <returns>한국어 인덱스</returns>
        public static int GetKoreanIndex(this string source, string keyword, IKoreanString koreanString)
        {
            return koreanString.GetKoreanMatchingStringIndex(source, keyword);
        }

        #endregion

        #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword, compareCharacterDelegate)

        /// <summary>
        /// 한국어 동일 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <param name="keyword">키워드</param>
        /// <param name="compareCharacterDelegate">문자 비교 대리자</param>
        /// <returns>한국어 동일 여부</returns>
        public static bool EqualKorean(this char source, char keyword, CompareCharacterDelegate compareCharacterDelegate)
        {
            return compareCharacterDelegate(source, keyword);
        }

        #endregion
        #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword)

        /// <summary>
        /// 한국어 동일 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <param name="keyword">키워드</param>
        /// <remarks>
        /// '한'.KEquals("ㅎ") -> true
        /// '한'.KEquals("하") -> true
        /// </remarks>
        /// <returns>한국어 동일 여부</returns>
        public static bool EqualKorean(this char source, char keyword)
        {
            return source.EqualKorean(keyword, PredefinedCharComparator.Default);
        }

        #endregion
        #region 한국어 동일 여부 구하기 - EqualKorean(source, keyword, koreanString)

        /// <summary>
        /// 한국어 동일 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <param name="keyword">키워드</param>
        /// <param name="koreanString">한국어 문자열 인터페이스</param>
        /// <returns>한국어 동일 여부</returns>
        public static bool EqualKorean(this char source, char keyword, IKoreanString koreanString)
        {
            return koreanString.EqualKorean(source, keyword);
        }

        #endregion

        #region 한국어 분리하기 - SeparateKorean(source)

        /// <summary>
        /// 한국어 분리하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <returns>분리한 한국어 문자열</returns>
        public static string SeparateKorean(this char source)
        {
            if(!source.IsInHangulSyllableRange())
            {
                return source.ToString();
            }

            StringBuilder stringBuilder = new StringBuilder();

            char chosung         = (char)(((int)source - HANGUL_SYLLABLE_START) / CHOSUNG_INTERVAL + HANGUL_JAMO_START);
            char joongsung       = (char)((((int)source - HANGUL_SYLLABLE_START) % CHOSUNG_INTERVAL) / JOONGSUNG_INTERVAL + HANGUL_JAMO_MOUM_START);
            char chosungLetter   = GetChosungLetter(chosung);
            char joongsungLetter = GetJoongsungLetter(joongsung);

            stringBuilder.Append(chosungLetter).Append(joongsungLetter);

            if(source.IsCharacterLevel3() == true)
            {
                char jongsung       = (char)((((int)source - HANGUL_SYLLABLE_START) % CHOSUNG_INTERVAL) % JOONGSUNG_INTERVAL + HANGUL_JAMO_JONGSUNG_START - 1);
                char jongsungLetter = GetJongsungLetter(jongsung);

                stringBuilder.Append(jongsungLetter);
            }

            return stringBuilder.ToString();
        }

        #endregion
        #region 한국어 분리하기 - SeparateKorean(source)

        /// <summary>
        /// 한국어 분리하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <remarks>
        /// "한".SeparateKorean() -> "ㅎㅏㄴ"
        /// </remarks>
        /// <returns>분리한 한국어 문자열</returns>
        public static string SeparateKorean(this string source)
        {
            StringBuilder stringBuilder = new StringBuilder();

            foreach(char character in source)
            {
                stringBuilder.Append(character.SeparateKorean());
            }

            return stringBuilder.ToString();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 범위 내 여부 구하기 - IsInRange(startCharacter, character, endCharacter)

        /// <summary>
        /// 범위 내 여부 구하기
        /// </summary>
        /// <param name="startCharacter">시작 문자</param>
        /// <param name="character">문자</param>
        /// <param name="endCharacter">종료 문자</param>
        /// <returns>범위 내 여부</returns>
        private static bool IsInRange(char startCharacter, char character, char endCharacter)
        {
            return (character >= startCharacter && character <= endCharacter);
        }

        #endregion
        #region 자모 범위 내 여부 구하기 - IsInJamoRange(source)

        /// <summary>
        /// 자모 범위 내 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <returns>자모 범위 내 여부</returns>
        private static bool IsInJamoRange(this char source)
        {
            return IsInRange(HANGUL_JAMO_START, source, HANGUL_JAMO_END) || IsInRange(HANGUL_LETTER_START, source, HANGUL_LETTER_END);
        }

        #endregion

        #region 초성 구하기 - GetChosung(source)

        /// <summary>
        /// 초성 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 예) [ㄱ] 문자 (0x3131) -> [ㄱ] 초성 (0x1100)
        /// </remarks>
        /// <returns>초성</returns>
        private static char GetChosung(this char source)
        {
            try
            {
                return _chosungDictionary[source];
            }
            catch(KeyNotFoundException)
            {
                return source;
            }
        }

        #endregion
        #region 초성 문자 구하기 - GetChosungLetter(source)

        /// <summary>
        /// 초성 문자 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <returns>초성 문자</returns>
        private static char GetChosungLetter(this char source)
        {
            try
            {
                return _reverseChosungDictionary[source];
            }
            catch(KeyNotFoundException)
            {
                return source;
            }
        }

        #endregion
        #region 중성 문자 구하기 - GetJoongsungLetter(source)

        /// <summary>
        /// 중성 문자 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 예) [ㅏ] 중성 (0x1161) -> [ㅏ] 문자 (0x314F)
        /// </remarks>
        /// <returns>중성 문자</returns>
        private static char GetJoongsungLetter(this char source)
        {
            try
            {
                return _reverseJoongsungDictionary[source];
            }
            catch(KeyNotFoundException)
            {
                return source;
            }
        }

        #endregion
        #region 종성 문자 구하기 - GetJongsungLetter(source)

        /// <summary>
        /// 종성 문자 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 예) [ㄱ] 종성 (0x11A8) -> [ㄱ] 문자 (0x3131)
        /// </remarks>
        /// <returns>종성 문자</returns>
        private static char GetJongsungLetter(this char source)
        {
            try
            {
                return _reverseJongsungDictionary[source];
            }
            catch(KeyNotFoundException)
            {
                return source;
            }
        }

        #endregion

        #region 한글 음절 범위 내 여부 구하기 - IsInHangulSyllableRange(source)

        /// <summary>
        /// 한글 음절 범위 내 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <returns>한글 음절 범위 내 여부</returns>
        private static bool IsInHangulSyllableRange(this char source)
        {
            return IsInRange(HANGUL_SYLLABLE_START, source, HANGUL_SYLLABLE_END);
        }

        #endregion

        #region 문자 레벨 1 여부 구하기 - IsCharacterLevel1(source)

        /// <summary>
        /// 문자 레벨 1 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 초성만으로 이루어진 글자인지 판별한다.
        /// ㅀ처럼 받침 전용 글자는 false로 판정한다.
        /// </remarks>
        /// <returns>문자 레벨 1 여부</returns>
        private static bool IsCharacterLevel1(this char source)
        {
            if(source.IsInJamoRange())
            {
                source = source.GetChosung();

                return IsInRange('\x1100', source, '\x1112');
            }
            else
            {
                return false;
            }
        }

        #endregion
        #region 문자 레벨 2 여부 구하기 - IsCharacterLevel2(source)

        /// <summary>
        /// 문자 레벨 2 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>초성 + 중성으로 이루어진 글자인지 판별한다.</remarks>
        /// <returns>문자 레벨 2 여부</returns>
        private static bool IsCharacterLevel2(this char source)
        {
            if(source.IsInHangulSyllableRange())
            {
                return (source - HANGUL_SYLLABLE_START) % JOONGSUNG_INTERVAL == 0;
            }
            else
            {
                return false;
            }
        }

        #endregion
        #region 문자 레벨 3 여부 구하기 - IsCharacterLevel3(source)

        /// <summary>
        /// 문자 레벨 3 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 초성 + 중성 + 종성으로 이루어진 글자인지 판별한다.
        /// 종성이 반드시 있어야 한다.
        /// </remarks>
        /// <returns>문자 레벨 3 여부</returns>
        private static bool IsCharacterLevel3(this char source)
        {
            return source.IsInHangulSyllableRange() && (!source.IsCharacterLevel2());
        }

        #endregion

        #region 자모 레벨 구하기 - GetJamoLevel(source)

        /// <summary>
        /// 자모 레벨 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <returns>자모 레벨</returns>
        private static int GetJamoLevel(this char source)
        {
            if(source.IsCharacterLevel1())
            {
                return 1;
            }
            else if(source.IsCharacterLevel2())
            {
                return 2;
            }
            else if(source.IsCharacterLevel3())
            {
                return 3;
            }
            else
            {
                return 0;
            }
        }

        #endregion

        #region 레벨 1 정규화 하기 - NormalizeLevel1(source)

        /// <summary>
        /// 레벨 1 정규화 하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 대상 유니코드를 정규화 한다 : 가, 각, 간, 감, 공, 괔, ... -> [ㄱ]
        /// </remarks>
        /// <returns>레벨 1 정규화 문자</returns>
        private static char NormalizeLevel1(this char source)
        {
            if(source.IsInJamoRange())
            {
                return source.GetChosung();
            }
            else if(source.IsInHangulSyllableRange())
            {
                return (char)((source - HANGUL_SYLLABLE_START) / CHOSUNG_INTERVAL + HANGUL_JAMO_START);
            }

            return source;
        }

        #endregion
        #region 레벨 2 정규화 하기 - NormalizeLevel2(source)

        /// <summary>
        /// 레벨 2 정규화 하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <remarks>
        /// 대상 유니코드를 정규화 한다 : 가, 각, 간, 감, 갛, ... -> [가]
        /// </remarks>
        /// <returns>레벨 2 정규화 문자</returns>
        private static char NormalizeLevel2(this char source)
        {
            return (char)(source - ((source - HANGUL_SYLLABLE_START) % JOONGSUNG_INTERVAL));
        }

        #endregion

        #region 레벨 1 자모 매칭 여부 구하기 - MatchLevel1Jamo(source, keyword)

        /// <summary>
        /// 레벨 1 자모 매칭 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <param name="keyword">키워드</param>
        /// <returns>레벨 1 자모 매칭 여부</returns>
        private static bool MatchLevel1Jamo(this char source, char keyword)
        {
            return source.NormalizeLevel1() == keyword.NormalizeLevel1();
        }

        #endregion
        #region 레벨 2 자모 매칭 여부 구하기 - MatchLevel2Jamo(source, keyword)

        /// <summary>
        /// 레벨 2 자모 매칭 여부 구하기
        /// </summary>
        /// <param name="source">소스 문자</param>
        /// <param name="keyword">키워드</param>
        /// <returns>레벨 2 자모 매칭 여부</returns>
        private static bool MatchLevel2Jamo(this char source, char keyword)
        {
            return source.NormalizeLevel2() == keyword;
        }

        #endregion
    }
}

 

728x90

 

▶ JosaType.cs

namespace TestProject
{
    /// <summary>
    /// 조사 타입
    /// </summary>
    public enum JosaType
    {
        /// <summary>
        /// 은, 는
        /// </summary>
        EN,

        /// <summary>
        /// 이, 가
        /// </summary>
        YG,

        /// <summary>
        /// 을, 를
        /// </summary>
        ER,

        /// <summary>
        /// 과, 와
        /// </summary>
        WG,

        /// <summary>
        /// 이다, 다
        /// </summary>
        YDD,

        /// <summary>
        /// 으로, 로 
        /// </summary>
        ERR
    }
}

 

300x250

 

▶ Program.cs

using System;

namespace TestProject
{
    /// <summary>
    /// 프로그램
    /// </summary>
    class Program
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 프로그램 시작하기 - Main()

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        private static void Main()
        {
            Console.WriteLine("동해물과 백두산이".EqualKorean("ㄷㅎㅁㄱ ㅂㄷㅅㅇ")); // true
            Console.WriteLine("동해물과 백두산이".EqualKorean("도해무과 ㅂㄷㅅㅇ")); // true
            Console.WriteLine("동해물과 백두산이".EqualKorean("ㄷㅎㅁㄱ ㅂㄷㅅ"  )); // false
 
            Console.WriteLine("동해물과 백두산이".ContainKorean("ㄷㅎㅁㄱ")); // true
            
            Console.WriteLine("동해물과 백두산이".GetKoreanIndex("ㄷㅎㅁㄱ")); // 0
            Console.WriteLine("동해물과 백두산이".GetKoreanIndex("ㅂㄷㅅ"  )); // 5
            
            Console.WriteLine("동해물과 백두산이".GetKoreanMatchingString("ㄷㅎㅁㄱ")); // "동해물과"
            Console.WriteLine("동해물과 백두산이".GetKoreanMatchingString("ㅂㄷㅅ"  )); // "백두산"
            
            Console.WriteLine("동해물과 백두산이".ExtractChosung()); // "ㄷㅎㅁㄱ ㅂㄷㅅㅇ"
            
            Console.WriteLine("동해물".AppendJosa(JosaType.WG)); // "동해물과"
            Console.WriteLine("백두산".AppendJosa("이", "가"));  // "백두산이"
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요