내가 작성한 방법들이 모든 경우를 해결해 주진 않지만.. 나의 경험을 토대로 여러 분들의 시간 절약에 도움이 되었으면 하여 올린다.
android:breakStrategy
가장 먼저 봐야할 것은 breakStrategy attribute다.
TextView | Android Developers
developer.android.com
사실 최근 버전들은 기본 strategy가 simple로 되어있기에 별 다른 설정을 해주지 않아도 된다.
하지만 Android 8.0(API 26) 환경에서 android:breakStrategy의 디폴트 값이 simple이 아닌 경우가 있다.
버전 별 디폴트 값을 분류해놓은 공식문서를 찾지는 못했지만, high-quality로 지정이 되어 있어서 직접 바꿔주지 않으면 아래와 같은 현상이 나타남에 주의하자.
모바일 개발자라면 다양한 버전에 대응할 수 있어야 하니까..
따옴표 쌍이 있으면 하나의 문자로 취급해요
android는 여러 종류의 따옴표가 있다. 그리고 모든 따옴표 쌍으로 감싼 문자열은 하나의 "문자"로 취급하는 듯 하다.
이러한 word-break 문제에 부딪혔다면, invisible zero-width space 로 변경해주면 된다. "\u200b"의 유니코드를 갖는 문자다.
binding.tvSomething.text = myStringData.replace(Regex("['\"`]"), "$0\u200b")
여러 공백 유니코드들을 검색해보고 싶다면 아래 사이트를 이용해보자.
Regular and Unusual "Space" Characters
Regular Space Characters U+0020 SPACE This is the regular space character as...
dev.to
왜 replace 두 번째 인자에 $0을 넣는가?
우리가 원하는 건 기존 따옴표를 [ 따옴표 + zero-width 공백 ] 형태로 바꿔, word-break가 무시되지 않도록 막는 것이다. 그렇지만 사용된 replace 함수는 문자열을 아예 치환하는 역할이 아닌가? 이 부분은 놀랍게도(?) Java의 정규표현으로 해결할 수 있다.
$n의 형태의 정규 표현이 있다. n은 0부터 9사이의 값만 유효하며, 각각의 숫자는 다른 역할을 한다. 예시로 설명하겠다.
<예시 문자열 = "A-5-B", 예시 정규식 = "([A-Z])-([0-9])-([A-Z])">
$0 : 매칭된 문자열 ("A-5-B")
$1 : $0의 결과 값 중 처음 괄호로 매칭된 문자열 ("A")
$2 : $0의 결과 값 중 두 번째 괄호로 매칭된 문자열 ("5")
$3 : $0의 결과 값 중 세 번째 괄호로 매칭된 문자열 ("B")
...
결론적으로, [ 매칭된 문자열 + ‘\u200b’(zero-width space: Unicode) ]의 형태로 바꾸었다고 해석이 가능하다.
따옴표는 종류도 여러 개에요
위의 해결 방법으로는 사실 상 모든 경우의 수를 막을 수 없다. 데이터를 보내주는 서버 측에서 알아서 항상 같은 문자로 해주면 좋겠지만, 공기업 서류 이름들 매칭되는 것만 봐도 그러기 쉽지 않다는 것을 알 수 있다.
‘ ’ ' 이 세 문자들이 달라 보이는가? 실제로 셋 다 다른 유니코드를 갖고 있다.
첫 번째 ‘ 는 ‘
두 번째 ’ 는 ’
세 번째 ' 는 '
실질적으로 예방하려면 아래와 같은 방식으로 작성하면 된다.
binding.tvSomething.text = myStringData.replace(Regex("[‘’“”'\"`]"), "$0\u200b")