알고리즘 문제를 풀다가 황당한 상황에 빠져서 기록에 남긴다.
습관처럼 테스트케이스를 드래그해서 콘솔에 붙여 넣었다.
1
6
6
1 5
3 4
5 4
4 2
4 6
5 2
그런데 첫 라인에 공백이 있었고 다음의 코드는 실패했다.
BufferedReader br = new BufferedReader(new StringReader(src));
int n = Integer.parseInt(br.readLine());
Exception in thread "main" java.lang.NumberFormatException: For input string: "1 "
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at se.code.d4.p5643_키순서.Solution.main(Solution.java:14)
공백이 있다니 trim()을 한방 먹여주면 해결될것 같았지만
int n = Integer.parseInt(br.readLine().trim());
Exception in thread "main" java.lang.NumberFormatException: For input string: "1 "
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at se.code.d4.p5643_키순서.Solution.main(Solution.java:14)
결과는 동일했다. java trim 메서드가 버그가 있다는 이야긴가?
당연히 그럴리는 없다. ㅜㅜ
문장을 구성하는 각 char들을 출력해보니 아래의 결과를 얻었다.
String line = br.readLine();
for(int i=0; i<line.length(); i++) {
char c = line.charAt(i);
System.out.printf("int: %d, char: ]%c[, %b\n", 0+c, c, Character.isWhitespace(c));
}
int: 49, char: ]1[, false
int: 160, char: ] [, false
int: 160, char: ] [, false
int: 160, char: ] [, false
int: 160, char: ] [, false
int: 160, char: ] [, false
int: 160, char: ] [, false
분명히 공백인데 Character.isWhitespace()를 보면 공백은 아니다. 그런데 희안한건 int로 변환한 값이 160이다. 즉 아스키 코드(~127)가 아니다.
unicode 160에 매핑된 키는 no-break space(줄바꿈 없는 공백: \u00A0)로 html에서 공백을 나타낼 때 사용하는 nbsp이다. 이런 값이 오는것도 신기한데 그 값이 공백이 아닌것은 더 신기하다.
trim 메서드의 설명에 보면 trim은 white space를 제거해주는데 \u0020 이하의 space character를 대상으로 한다. 따라서 \u00A0은 대상이 아니다.
이 문자열을 처리하기 위해서는 replace로 대체시켜야 한다.
int tc = Integer.parseInt(br.readLine().replace("\u00a0", ""));
Character 클래스의 isWhitespace() 메서드를 보면 어떤 문자를 공백문자로 인식하는지 알 수 있다.
It is a Unicode space character (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR)
but is not also a non-breaking space ('\u00A0', '\u2007', '\u202F').
It is '\t', U+0009 HORIZONTAL TABULATION.
It is '\n', U+000A LINE FEED.
It is '\u000B', U+000B VERTICAL TABULATION.
It is '\f', U+000C FORM FEED.
It is '\r', U+000D CARRIAGE RETURN.
It is '\u001C', U+001C FILE SEPARATOR.
It is '\u001D', U+001D GROUP SEPARATOR.
It is '\u001E', U+001E RECORD SEPARATOR.
It is '\u001F', U+001F UNIT SEPARATOR.
\u00A0는 안된단다.
특히 웹을 통해서 전달되는 데이터가 있다면 조심할 필요가 있다.