소개
- 알고리즘 스터디를 참여하며 작성하는 TIL입니다.
- TIL란? 'Today I Learned'약자로 한국어로 번역하면 '오늘 내가 배운 것'이란 의미입니다.
- 제가 오늘 하루 배운 것 혹은 경험하고 느낀 것들을 기록하고 회고하는 습관을 기르기 위한 글입니다.
문제 & 키워드
- 프로그래머스 - 숫자 문자열과 영단어(문제 링크)
- replace
- replaceAll
문제 설명
다음은 숫자의 일부 자릿수를 영단어로 바꾸는 예시입니다.
- 1478 → "one4seveneight"
- 234567 → "23four5six7"
- 10203 → "1zerotwozero3"
이렇게 숫자의 일부 자릿수가 영단어로 바뀌어졌거나, 혹은 바뀌지 않고 그대로인 문자열 s가 매개변수로 주어집니다. s가 의미하는 원래 숫자를 return 하도록 solution 함수를 완성하면 됩니다.
참고로 각 숫자에 대응되는 영단어는 다음 표와 같습니다.
숫자 영단어
0 | zero |
1 | one |
2 | two |
3 | three |
4 | four |
5 | five |
6 | six |
7 | seven |
8 | eight |
9 | nine |
해결 조건
- 문제 해결을 위한 핵심 조건은 다음과 같습니다.
- 숫자의 일부 자릿수가 영단어로 바뀐게 있다면 다시 숫자로 바꾸어 return 한다.
- 숫자에 대응되는 영단어는 정해져 있다.
문제 풀이 - Map과 replace활용
import java.util.Map;
class Solution {
public static int solution(String s) {
// 1
Map<String, String> numberConvertMap = Map.of(
"0", "zero",
"1", "one",
"2", "two",
"3", "three",
"4", "four",
"5", "five",
"6", "six",
"7", "seven",
"8", "eight",
"9", "nine"
);
// 2
for (Map.Entry<String, String> entry : numberConvertMap.entrySet()) {
s = s.replace(entry.getValue(), entry.getKey());
}
// 3
return Integer.parseInt(s);
}
}
- 영단어가 동적인 값이 아닌 정해져 있고 숫자와 1:1로 매핑되기 때문에 Map을 사용하여 각 영단어와 숫자를 key와 value로 저장한 후, 입력 문자열을 해당 영단어를 숫자로 replace하는 방법을 사용했습니다.
구체적인 구현 방법은 다음과 같습니다.
- 영단어와 숫자를 Map에 key와 value로 저장합니다.
- Map 을 순회하면서 Map에 있는 각 영단어를 replace를 활용해 value를 key로 대체합니다.
- replace는 기존 문자를 계속해서 바꾸는게 아닌 새로운 문자열을 반환하기 때문에 반환된 값을 입력받은 변수s에 담아주며 반복합니다.
- 최종적으로 모든 영단어가 숫자로 대체된 문자열을 숫자로 변환해 반환합니다.
이 과정을 통해 코드의 가독성을 유지하면서도 효율적으로 문제를 해결할 수 있습니다.
replace말고 replaceAll을 써야 하는 것 아닌가?
replaceAll 메서드의 이름만 보고 특정 문자열을 지정한 문자열로 모두 바꿀 것이라고 생각하고, replace 메서드는 처음 찾은 문자열만 지정한 문자열로 바꾼다고 오해할 수 있습니다.
결론적으로, replace 메서드도 특정 문자열을 지정한 문자열로 ‘모두’ 바꿉니다. 두 메서드 간의 차이는 매개변수의 유형과 동작 방식에 있습니다.
아래는 replace와 replaceAll 메서드의 매개변수 차이입니다.
String replace(CharSequence target, CharSequence replacement);
String replaceAll(String regex, String replacement);
replace 메서드는 CharSequence 타입의 target과 replacement를 매개변수로 받아, target으로 지정된 모든 문자열을 replacement로 대체합니다. 이는 단순한 문자열 치환을 수행하며 정규 표현식을 지원하지 않습니다.
반면에, replaceAll 메서드는 String 타입의 regex와 replacement를 매개변수로 받아, 정규 표현식으로 매칭되는 모든 문자열을 replacement로 대체합니다. replaceAll은 정규 표현식을 사용하여 보다 복잡한 문자열 패턴 매칭 및 치환을 수행할 수 있습니다.
다음은 예시 코드로 replace와 replaceAll 메서드의 동작 방식 차이를 설명합니다.
public class Example {
public static void main(String[] args) {
String str = "hello.world.my.name.is.dami";
String replace = str.replace(".", "/");
String replaceAll = str.replaceAll(".", "/");
System.out.println("replace = " + replace);
System.out.println("replaceAll = " + replaceAll);
}
}
/**
* 출력 결과
* replace = hello/world/my/name/is/dami
* replaceAll = ///////////////////////////
*/
위 코드에서 replace 메서드는 입력받은 문자열 '.'을 모두 '/'로 바꾼 것을 확인할 수 있습니다. 반면에, replaceAll 메서드는 '.'을 정규 표현식으로 인식하여 문자열의 모든 문자를 '/'로 바꾼 결과를 보여줍니다.
replaceAll 메서드도 동일한 결과를 얻으려면, 정규 표현식의 '.'을 리터럴 점 문자로 인식하도록 이스케이프 처리를 해야 합니다. 이를 위해 '\\.'를 사용합니다.
다음은 수정된 코드입니다.
public class Example {
public static void main(String[] args) {
String str = "hello.world.my.name.is.dami";
String replace = str.replace(".", "/");
String replaceAll = str.replaceAll("\\.", "/");
System.out.println("replace = " + replace);
System.out.println("replaceAll = " + replaceAll);
}
}
/**
* 출력 결과
* replace = hello/world/my/name/is/dami
* replaceAll = hello/world/my/name/is/dami
*/
이렇게 replaceAll 메서드에서 '\\.'을 사용하면 점 문자를 리터럴로 인식하여 원하는 대로 모든 '.'을 '/'로 대체할 수 있습니다.
마무리하며
- 숫자 문자열과 영단어 변환 문제를 해결하기 위해 replace와 replaceAll 메서드를 활용하는 방법을 살펴보았습니다. replace 메서드는 단순히 문자열 치환을 수행하며, 모든 일치하는 문자열을 지정한 문자열로 대체합니다. 반면, replaceAll 메서드는 정규 표현식을 사용하여 보다 복잡한 패턴 매칭 및 치환을 가능하게 합니다.