Machineboy空

Excercism - Wordy 문자열 다루기, Split, Replace, int.tryParse 본문

Computer/Coding Test

Excercism - Wordy 문자열 다루기, Split, Replace, int.tryParse

안녕도라 2025. 2. 20. 12:44

문제요약

문자열로 이루어진 수식을 계산하여라.

 

https://exercism.org/tracks/csharp/exercises/wordy

 

Wordy in C# on Exercism

Can you solve Wordy in C#? Improve your C# skills with support from our world-class team of mentors.

exercism.org


난이도

Medium


풀이 포인트

  • 문자열 다루기 : What is  ~ ? 꼴의 문자열을 원하는 방식으로 자르기
  • 예외 처리
    • 수와 수 사이에 연산자가 없을 때 : minus 1 2
    • 이상한 문장이 들어왔을 때: what is your name?

REVIEW

 

이런 문제는 차력으로 풀리기 때문에 또 차력으로 풀었다.

 

문자열이 숫자인지 판단하는 방법으로

  • int.TryParse(string, out int)가 있다는 것을 알았고,

 

원하는 문자만 남기는 방법으로 아래와 같은 방법이 있다는 것을 알았다.

  • SubString()
  • Replace("없애고픈 문자", "")
  • List.RemoveAll(x => x == "by")

LINQ 사용은 좀처럼 익숙해지지가 않는다. 우선은 직관적인 SubString과 Replace에 익숙해지도록 하고,

좀 더 친해져 보기로. LINQ를 다루지 못하면서 C# 언어를 할 줄 안다고 말하긴 좀 껄끄러우니.

나의 차력 풀이(모든 예외 케이스를 각 조건식으로 따로 처리하는 코드)와

모범 코드(예외 케이스간의 공통점을 찾아내 하나의 조건식으로 처리하는 코드) 기록해둔다.

 


CODE

using System;
using System.Collections.Generic;

public static class Wordy
{
    public static int Answer(string question)
    {    
        // 수와 연산 기호만 남기고 나머지 삭제
        if (question == "What is?") throw new ArgumentException();
        string questionEdit = question.Substring(8);
        questionEdit = questionEdit.Substring(0, questionEdit.Length-1);

        
        string[] splited = questionEdit.Split(' ');
        List<string> splitedList = new List<String>(splited);
        splitedList.RemoveAll(x => x == "by");

    

        List<string>admission = new List<string>{"minus","plus","multiplied","divided"};

        // 수와 연산 기호 따로 관리
        List<int> number = new List<int>();
        List<string>operation = new List<string>();

        for(int i = 0; i < splitedList.Count; i++)
        {           
            // 숫자일 경우에만 추가
            if (i%2 == 0 && int.TryParse(splitedList[i], out int num))
            {
                number.Add(num);
            }
            else
            {
                // 연산자일 경우에만 추가
                if (admission.Contains(splitedList[i]))
                {
                    operation.Add(splitedList[i]);
                }
                else
                {
                    // 숫자도 아니고 연산자도 아니면 예외 발생
                    throw new ArgumentException();
                }
            }
        }
        
        if(number.Count - operation.Count != 1)
        {
            throw new ArgumentException();
        }

        if(number.Count == 1)
        {
            return number[0];
        }
        
        // 앞에서 부터 연산
        int answer = -1;

        answer = operate(number[0],number[1],operation[0]); 

        if(number.Count > 2){
        for(int i = 2; i < number.Count; i++)
        {
            answer = operate(answer, number[i], operation[i-1]);
        }
    }
        return answer;
    }

    public static int operate(int a, int b, string op)
    {
        switch(op)
        {
            case "plus":
                return a + b;
            case "minus":
                return a - b;
            case "multiplied":
                return a * b;
            case "divided":
                return a/b;
            default:
                throw new ArgumentException();
        }
    }
}
using System;

public static class Wordy
{
    public static int Answer(string question)
    {
        int total;

        //Clean out some junk
        question = question.Replace("What is ", "");
        question = question.Replace("?", "");
        question = question.Replace("multiplied by", "multiplied");
        question = question.Replace("divided by", "divided");

//Separate the problem by space
        string[] parts = question.Split(' ');
        if (parts.Length == 1)
        {
            total = int.Parse(parts[0]);
        }
        else if (parts.Length == 3)
        {
            if (int.TryParse(parts[0], out _) == false ||
                int.TryParse(parts[2], out _) == false)
            {
                throw new ArgumentException();
            }
            //The problem is number operator number (e.g. 1 + 1)
            total = ProcessParts(parts[0], parts[1], parts[2]);
        }
        else if (parts.Length == 5)
        {
            if (int.TryParse(parts[0], out _) == false ||
                int.TryParse(parts[2], out _) == false ||
                int.TryParse(parts[4], out _) == false)
            {
                throw new ArgumentException();
            }
            //The problem is number operator number operator number (e.g. 1 + 1 + 1)
            total = ProcessParts(parts[0], parts[1], parts[2]);
            //Use the first result and add it to the second part
            total = ProcessParts(total.ToString(), parts[3], parts[4]);
        }
        else
        {
            //Otherwise the format is weird, chunk it,
            throw new ArgumentException();
        }

        return total;
    }

    private static int ProcessParts(string part1, string part2, string part3)
    {
        int p1 = int.Parse(part1);
        int p3 = int.Parse(part3);
        if (part2 == "plus")
        {
            return p1 + p3;
        }
        else if (part2 == "minus")
        {
            return p1 - p3;
        }
        else if (part2 == "multiplied")
        {
            return p1 * p3;
        }
        else if (part2 == "divided")
        {
            return p1 / p3;
        }
        else
        {
            return 0;
        }
    }
}