--- tags: README --- # ๐Ÿงฎ ๊ณ„์‚ฐ๊ธฐ [STEP 2] > ํ”ผ์—ฐ์‚ฐ์ž์™€ ์—ฐ์‚ฐ์ž ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ์ „๋‹ฌํ•˜๋ฉด ์ด๋ฅผ ์—ฐ์‚ฐ์ž ๊ธฐ์ค€์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ์ˆซ์ž(Double)๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. >> **๋น„๊ณ ์‚ฌํ•ญ** >> 1. <details><summary>(Toggle) <U>์ •ํ•ด์ง„ UML</U>์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํƒ€์ž…์„ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.</summary><div markdown="1"><img src="https://hackmd.io/_uploads/ByY8jQJvn.png"></div></details> >> 2. STEP 1์—์„œ ๊ตฌํ˜„ํ•œ Queue๋ฅผ ํ™œ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. <br><br> ## ๋ชฉ์ฐจ๐Ÿ“Œ 1. [ํŒ€์›์†Œ๊ฐœ](##ํŒ€์›์†Œ๊ฐœ๐Ÿ‘ฉโ€๐Ÿ’ป) 2. [ํƒ€์ž„๋ผ์ธ](##ํƒ€์ž„๋ผ์ธ๐Ÿ—“๏ธ) 3. [๋‹ค์ด์–ด๊ทธ๋žจ](##๋‹ค์ด์–ด๊ทธ๋žจ๐Ÿ“Š) 4. [ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…](##ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…๐Ÿšจ) 5. [์ฐธ๊ณ ์ž๋ฃŒ](##์ฐธ๊ณ ์ž๋ฃŒ๐Ÿ“˜) 6. [ํšŒ๊ณ ](##ํšŒ๊ณ ๐Ÿ“) <br><br> ## ํŒ€์›์†Œ๊ฐœ๐Ÿ‘ฉโ€๐Ÿ’ป | <img src="https://hackmd.io/_uploads/r1rWKewLn.png" width="200"/> | | :-: | | [**maxhyunm**](https://github.com/maxhyunm)<br/> | <br><br> ## ํƒ€์ž„๋ผ์ธ๐Ÿ—“๏ธ ์ž‘์—… ์ง„ํ–‰ ๊ธฐ๊ฐ„ | 23.06.01.(๋ชฉ) ~ 23.06.08.(๊ธˆ) | ๋‚ ์งœ | ์ง„ํ–‰ ์‚ฌํ•ญ | | -------- | -------- | | 23.06.01.(๋ชฉ) | Operator ํƒ€์ž… ์ƒ์„ฑ<br/>โ†ณ add(), subtract(), multiply(), divide() ๋ฉ”์„œ๋“œ ํ…Œ์ŠคํŠธ / ๊ตฌํ˜„ / ๋ฆฌํŒฉํ† ๋ง <br/><br/>Formula ํƒ€์ž… ์ƒ์„ฑ<br/>โ†ณ result() ๋ฉ”์„œ๋“œ ํ…Œ์ŠคํŠธ / ๊ตฌํ˜„ / ๋ฆฌํŒฉํ† ๋ง<br/><br/>EspressionParsor ํƒ€์ž… ์ƒ์„ฑ<br/>โ†ณ parse() ๋ฉ”์„œ๋“œ ํ…Œ์ŠคํŠธ / ๊ตฌํ˜„ / ๋ฆฌํŒฉํ† ๋ง<br/>โ†ณ componentsByOperators() ๋ฉ”์„œ๋“œ ํ…Œ์ŠคํŠธ / ๊ตฌํ˜„ / ๋ฆฌํŒฉํ† ๋ง| | 23.06.02.(๊ธˆ) |ExpressionParser ๋ฆฌํŒฉํ† ๋ง, ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€<br/>CalculatorItemNode์— ์ œ๋„ค๋ฆญ ์„ค์ • ์ถ”๊ฐ€<br/>ํŒŒ์ผ ์œ„์น˜ ์ •๋ฆฌ | | 23.06.03.(ํ† ) |์ œ๋„ค๋ฆญ ํƒ€์ž…๋ช… ์ˆ˜์ •(T->Element) | | 23.06.05.(์›”) |ํ•„์š”์—†๋Š” ๋ณ€์ˆ˜ ์ œ๊ฑฐ, ๊ฐœํ–‰ ์ถ”๊ฐ€ | | 23.06.08.(๋ชฉ) |README ์ž‘์„ฑ | <br><br> ## ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…๐Ÿšจ ### 1๏ธโƒฃ ํƒ€์ž…์บ์ŠคํŒ… <br> ๐Ÿ”’ **๋ฌธ์ œ์ ** >์—ฐ์‚ฐ์„ ์œ„ํ•œ Queue๋Š” CalculateItem ํ˜•ํƒœ๋กœ ์š”์†Œ๋ฅผ ์ €์žฅํ•˜๊ณ , ์‹ค์ œ ์—ฐ์‚ฐ์€ CalculateItem์„ ์ค€์ˆ˜ํ•˜๋Š” Double๊ณผ Operator ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋‹ค ๋ณด๋‹ˆ ๋งค๋ฒˆ ๋‹ค์šด์บ์ŠคํŒ…์„ ํ•ด์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ```swift= while true { do { guard let rhs = try operands.dequeue() as? Double else { throw CalculatorError.invalidInput } ... guard let newOperator = try operators.dequeue() as? Operator else { throw CalculatorError.invalidOperator } ... ``` ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** >QueueType์— associatedtype์„ ์ถ”๊ฐ€ํ•˜๊ณ , ํ•ด๋‹น ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…๋“ค๊ณผ CalculateItemNode ํƒ€์ž…์— ์ œ๋„ค๋ฆญ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํƒ€์ž…์บ์ŠคํŒ… ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค. ```swift= protocol QueueType { associatedtype Item where Item: CalculateItem mutating func enqueue(_ value: Item) mutating func dequeue() throws -> Item mutating func removeAll() } ``` ```swift= class CalculatorItemNode<Element: CalculateItem> { private(set) var value: Element private(set) var next: CalculatorItemNode? init(_ value: Element) { self.value = value } ... ``` --- ### 2๏ธโƒฃ parse() ๋งˆ์ด๋„ˆ์Šค ๋ถ€ํ˜ธ ์ฒ˜๋ฆฌ<br> ๐Ÿ”’ **๋ฌธ์ œ์ **<br> >๋นผ๊ธฐ ์—ฐ์‚ฐ์ž์™€ ๋งˆ์ด๋„ˆ์Šค๋ถ€ํ˜ธ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ์žˆ์–ด ๊ณ ๋ฏผ์ด ๋งŽ์•˜์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ๋งˆ์ด๋„ˆ์Šค ๋ถ€ํ˜ธ๋ฅผ "!"๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ง„ํ–‰ ํ›„ ๋‹ค์‹œ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ, ๋„ˆ๋ฌด ๋น„ํšจ์œจ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ```swift= static func parse(from input: String) throws -> Formula { ... let operatorWithMinus = [(before: "+-", after: "+!"), (before: "--", after: "-!"), (before: "/-", after: "/!"), (before: "*-", after: "*!")] let inputValue = operatorWithMinus.reduce(input) { inputString, operatorType in inputString.replacingOccurrences(of: operatorType.before, with: operatorType.after) } ... } static private func componentsByOperators(from input: String) -> [String] { ... inputValues = inputValues.replacingOccurrences(of: "!", with: "-") ... } ``` ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** <br> > ์Šคํ† ๋ฆฌ๋ณด๋“œ ๋ฒ„ํŠผ ํƒ€์ดํ‹€๊ฐ’์œผ๋กœ ๋“ค์–ด๊ฐ„ ๋นผ๊ธฐ ์—ฐ์‚ฐ์ž๊ฐ€ ๋งˆ์ด๋„ˆ์Šค ๋ถ€ํ˜ธ์™€ ๋น„์Šทํ•œ ํ˜•ํƒœ์ด์ง€๋งŒ ์‚ด์ง ๋‹ค๋ฅธ ๋ฌธ์ž์—ด๋กœ ๋˜์–ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ์•˜๊ณ , ์ด ๋ฌธ์ž์—ด์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•˜๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งˆ์ด๋„ˆ์Šค ๋ถ€ํ˜ธ์™€ ๊ตฌ๋ถ„์ด ๋  ๊ฒƒ์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋•๋ถ„์— ๋ณต์žกํ–ˆ๋˜ ๋กœ์ง์ด ๋งค์šฐ ๊ฐ„๊ฒฐํ•ด์กŒ์Šต๋‹ˆ๋‹ค. ```swift= static func parse(from input: String) -> Formula { ... let operandComponents = self.componentsByOperators(from: input).compactMap { Double($0) } let operatorComponents = input.compactMap { Operator(rawValue: $0) } ... } ``` --- ### 3๏ธโƒฃ ExpressionParser ๋ฉ”์„œ๋“œ ๊ธฐ๋Šฅ ๋ถ„๋ฆฌ<br> ๐Ÿ”’ **๋ฌธ์ œ์ **<br> >์ด๋ฏธ ์ž‘์„ฑ๋œ UML์„ ํ† ๋Œ€๋กœ ์ง„ํ–‰ํ•˜๋‹ค ๋ณด๋‹ˆ ๊ฐ ๋ฉ”์„œ๋“œ์˜ ์—ญํ• ์ด ์–ด๋–ค ๊ฒƒ์ธ์ง€ ํ™•์‹คํžˆ ํŒŒ์•…ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ 1๋ฒˆ์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์ „์—๋Š” ๋งˆ์ด๋„ˆ์Šค ๋ถ€ํ˜ธ ๋ถ€๋ถ„๊นŒ์ง€ ํฌํ•จํ•˜์—ฌ ๋กœ์ง์ด ๋”์šฑ ๋ณต์žกํ•˜๊ณ , ๊ธฐ๋Šฅ๋ณ„๋กœ ๋ฉ”์„œ๋“œ๊ฐ€ ์ œ๋Œ€๋กœ ๊ตฌ๋ณ„๋œ ๋А๋‚Œ์ด ๋“ค์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํŠนํžˆ componentsByOperators() ๊ฐ™์€ ๊ฒฝ์šฐ ์—ฐ์‚ฐ์ž๋ฅผ ํ† ๋Œ€๋กœ ๋ฌธ์ž์—ด์„ ์ชผ๊ฐœ๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋งž๋Š”์ง€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์•„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ```swift static private func componentsByOperators(from input: String) -> [String] { let allOperators = Operator.allCases.map { $0.rawValue } var inputValues = allOperators.reduce(input) { inputString, operatorType in inputString.split(with: operatorType).joined(separator: "|") } inputValues = inputValues.replacingOccurrences(of: "!", with: "-") let result = inputValues.split(with: "|") return result } ``` ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** <br> >๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์„ ํ† ๋Œ€๋กœ ์ •ํ™•ํžˆ ์–ด๋–ค ์—ญํ• ์„ ํ•ด์•ผํ•˜๋Š”์ง€๋ฅผ ์žฌ์ •๋ฆฌํ–ˆ๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ถˆํ•„์š”ํ•œ ๋กœ์ง์„ ์ณ๋‚ด์–ด ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์„ ๊ฑฐ์น˜๋ฉด์„œ ์ „์ฒด์ ์ธ ๋กœ์ง์ด ์–ด๋–ค ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•˜๋Š”์ง€๋„ ์กฐ๊ธˆ ๋” ๋ช…ํ™•ํ•ด์กŒ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ return์—์„œ ๋ฐ”๋กœ ํ•จ์ˆ˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ณ€์ˆ˜ ์‚ฌ์šฉ์„ ์ค„์˜€์Šต๋‹ˆ๋‹ค. ```swift= static private func componentsByOperators(from input: String) -> [String] { return Operator.allCases.reduce([input]) { resultArray, operatorItem in resultArray.map { $0.split(with:operatorItem.rawValue) }.flatMap { $0 } } } extension String { func split(with target: Character) -> [String] { return components(separatedBy: String(target)) } } ``` --- ### ๐Ÿค” ๊ณ ๋ฏผํ–ˆ๋˜ ์  <br> > ์ด๋ฏธ ์ •๋ฆฌ๋œ UML์„ ํ† ๋Œ€๋กœ ํƒ€์ž…๊ณผ ๋ฉ”์„œ๋“œ์˜ ์—ญํ• ์„ ์ถ”๋ก ํ•˜๋ฉฐ ์ž‘์—…ํ•˜๋Š” ๋ฐฉ์‹์ด ์ต์ˆ™ํ•˜์ง€ ์•Š์•„์„œ ํ‰์†Œ๋ณด๋‹ค ๋Œ€๋Œ€์ ์ธ ๋ฒ”์œ„๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ๋ฐ˜๋ณตํ–ˆ๋˜ ์Šคํ…์ž…๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” TDD๋ฅผ ์ค€์ˆ˜ํ•˜๋ ค ํ–ˆ์ง€๋งŒ, ์ด ๊ณผ์ •์—์„œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์„  ๊ตฌํ˜„ ํ›„ ์œ ๋‹›ํ…Œ์ŠคํŠธ ํ˜•์‹์œผ๋กœ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ž‘์—…์— ๋“ค์–ด๊ฐ€๊ธฐ ์ „์— ๊ฐ ํƒ€์ž…์— ๋Œ€ํ•œ ์ถฉ๋ถ„ํ•œ ๊ณ ๋ฏผ๊ณผ ์ƒ์„ธํ•œ ์ •๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. <br><BR> ## ์ฐธ๊ณ ์ž๋ฃŒ๐Ÿ“˜ - [The Swift Programming Language - Generics](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/generics/) - [Apple Developer Documentation - reduce(_: _:)](https://developer.apple.com/documentation/swift/array/reduce(_:_:)) - [Apple Developer Documentation - map(_:)](https://developer.apple.com/documentation/swift/array/map(_:)-87c4d) - [Apple Developer Documentation - flatMap(_:)](https://developer.apple.com/documentation/swift/array/flatmap(_:)-6chu8) <br><BR> ## ํšŒ๊ณ ๐Ÿ“ ๐Ÿ‘ ์ต์ˆ™ํ•˜์ง€ ์•Š์•˜๋˜ ์ œ๋„ค๋ฆญ ์‚ฌ์šฉ๊ณผ ๊ณ ์ฐจํ•จ์ˆ˜ ์‚ฌ์šฉ์„ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ๊ตฌํ˜„์— ์„ฑ๊ณตํ•œ ์  ๐Ÿ‘ ์‹œ๊ฐ„ ๋‚ด์— ์ž˜ ๋งˆ๋ฌด๋ฆฌํ•œ ์  ๐Ÿ‘Ž ์‚ฌ์ „์— ํƒ€์ž…๊ณผ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ํŒŒ์•…์„ ์ถฉ๋ถ„ํžˆ ์ง„ํ–‰ํ•˜์ง€ ์•Š์•„ ๋งŽ์€ ์ˆ˜์ •์„ ๊ฑฐ์นœ ์ 