NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (텍스트 유사율 체크 조건)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 이전 시간에 배열 정렬에 대해 알아봤는데요. 배열을 정렬할 때 "텍스트를 좀 더 다이나믹하게 정렬할 수 없을까?" 하는 의문이 들었습니다. 그래서 텍스트중에서 특정 단어와 유사한 정도가 높거나 낮은 순서로 정렬하는건 어떨까 생각 해봤습니다. 이 기능이 꼭 필요한건 아닐거예요. 하지만, 어차피 텍스트 유사율을 체크할 수 있는 조건을 만들어야 하고, 이 기능을 접목할 수 있다면 좋을겁니다. 그래서, 배열 정렬에 대한 내용을 잠시 멈추고 텍스트 유사율 체크 조건을 먼저 만들기로 했습니다. 어차피 해야 하니까요^^

     

    아래와 같이 컨디션안에 TextSimilarityCheckModel 모델을 하나 추가했습니다.

    gJrj5hK.png

     

     

    텍스트 유사율 체크는 조건이기 때문에 CheckModel을 상속 받아서 구현해야 합니다. 기본 조건의 결과뿐만 아니라 몇가지 정보를 더 제공해야 합니다. 그래서, MatchRateResult와 MismatchCountResult가 데이타 영역에 추가되어 있습니다. 일단 이들은 조건을 어떻게 처리할지에 따라서 결과가 달라지고, 참과 거짓 처리가 결정됩니다.

    [LocalizedCategory("Data")]
    [LocalizedDisplayName("MatchRateResult")]
    [LocalizedDescription("MatchRateResult")]
    [Browsable(true)]
    [DefaultValue(0d)]
    [ReadOnly(true)]
    public double MatchRateResult { get; set; }
    
    [LocalizedCategory("Data")]
    [LocalizedDisplayName("MismatchCountResult")]
    [LocalizedDescription("MismatchCountResult")]
    [Browsable(true)]
    [DefaultValue(0)]
    [ReadOnly(true)]
    public int MismatchCountResult { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("SimilarityRate")]
    [LocalizedDescription("SimilarityRate")]
    [Browsable(true)]
    [DefaultValue(80)]
    public int SimilarityRate { get; set; } = 80;
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("MismatchCount")]
    [LocalizedDescription("MismatchCount")]
    [Browsable(true)]
    [DefaultValue(1)]
    public int MismatchCount { get; set; } = 1;
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("MatchTypeOption")]
    [LocalizedDescription("MatchTypeOption")]
    [Browsable(true)]
    [DefaultValue(typeof(Ai.Definition.MatchTypeOption), "SimilarityRate")]
    public Ai.Definition.MatchTypeOption MatchTypeOption { get; set; } = Definition.MatchTypeOption.SimilarityRate;

     

    조건을 처리하는 옵션은 2개를 제공합니다. A와 B 텍스트의 유사율이 80프로 이상이면 참이라고 체크할 수 있고, MismatchCount는 A와 B 텍스트에서 다른 부분의 수를 체크합니다. 따라서, 이 둘은 서로 반대로 동작하게 됩니다. 유사율은 사용자가 설정한 값보다 크면 참이고, 다른 문자 수는 설정 값보다 크면 참이 됩니다.

    public enum MatchTypeOption
    {
        SimilarityRate = 0,
        MismatchCount = 1
    }

     

    아래는 프로세스 전체 코드입니다.

    public override string? Execute(IPlayer player)
    {
        MatchRateResult = 0d;
        MismatchCountResult = 0;
    
        var id = base.Execute(player);
    
        int n = LeftValue.Length;
        int m = RightValue.Length;
        int[,] d = new int[n + 1, m + 1];
    
        for (int i = 0; i <= n; d[i, 0] = i++);
        for (int j = 1; j <= m; d[0, j] = j++);
    
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                int cost = (RightValue[j - 1] == LeftValue[i - 1]) ? 0 : 1;
                int min1 = d[i - 1, j] + 1;
                int min2 = d[i, j - 1] + 1;
                int min3 = d[i - 1, j - 1] + cost;
                d[i, j] = System.Math.Min(System.Math.Min(min1, min2), min3);
            }
        }
    
        MismatchCountResult = d[n, m];
        MatchRateResult = (double)(LeftValue.Length - MismatchCountResult) / LeftValue.Length * 100;
    
        switch (MatchTypeOption)
        {
            case MatchTypeOption.SimilarityRate:
                ConditionResult = MatchRateResult == 100 ? true : MatchRateResult > SimilarityRate;
                break;
            case MatchTypeOption.MismatchCount:
                ConditionResult = MismatchCountResult == 0 ? false : MismatchCountResult > MismatchCount;
                break;
        }
    
        player.Manager.Output.WriteLine(
            $"{player.Manager.Client.ResxCaption.GetString("MatchTypeOption")}:{MatchTypeOption}, 
            {player.Manager.Client.ResxCaption.GetString(nameof(LeftValue))}:
            {LeftValue}, {player.Manager.Client.ResxCaption.GetString(nameof(RightValue))}:
            {RightValue}", log4net.Core.Level.Debug);
    
        Common.ConditionProcess(this, ref id);
    
        return id;
    }

     

    로직은 간단합니다. 왼쪽 텍스트와 오른쪽 텍스트를 변수에 추가하고, 길이를 계산합니다. 그리고, 길이 차이만큼 빼주고 하나씩 비교하면서 차이나는 문자의 수를 세서 배열에 저장합니다. 이 값이 나중에 미스매치 카운트가 됩니다. 매스매치 카운트를 백분율로 변환하면 배율 조건으로 사용할 수 있습니다. 간단한 산수라서 코드를 유심히 보시면 어떻게 동작되는지 쉽게 이해할 수 있습니다.

     

    이제 정상적으로 동작하는지 테스트를 해볼까요? 테스트는 약간 복잡하지만, 아래 동영상 내용을 보면 쉽게 이해할 수 있을겁니다.

     

     

    다음 시간에는 배열의 정렬 기능을 좀 더 확장 해볼 생각입니다. 가까운 순서와 먼 순서 그리고, 유사도와 특정 숫자와 가깝거나 먼 순서등등... 해야 할 내용들이 많을거 같아요. 아무래도 변수에 추가할 수 있는 자료형이 다양하다보니 유연하게 대응하려면 기능이 많고 복잡해질 수밖에 없습니다. 그래서, 가능하면 기본 기능만 제공하고 사용자가 알아서 커스텀 모듈화 하거나 추상화된 기존 액션을 확장하는 방법으로 사용하도록 하고 싶었는데요.

     

    대부분의 매크로 사용자분들이 개발자가 아닌데다가 쉽게 사용하는게 더 좋기 때문에 미리 만들어진 코드를 자유롭게 사용할 수 있도록 옵션을 제공하는 방식으로 개발하게 되었습니다. 어쩔 수 없는 부분입니다. 그렇다보니 사용하는 몇가지의 핵심 기능 외에도 다양한 기능들이 포함되어 있어서 약간의 성능 저하를 감수해야 합니다. 최적화된 액션 라이브러리를 따로 배포하는 것도 좋은 방법일거 같은데요. 아직 먼~ 이야기입니다. 언젠가는 해야 할 일이긴 하지만, 지금은 아니죠^^

     

    이 글이 도움이 되셨다면~ 커피 한잔이라도 후원 부탁드립니다^^

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

     

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.