IT/JAVA | Spring
[JAVA] 특수문자 > 숫자(0123~순, 소수점 포함) > 영어(대문자 먼저, abc~순) > 한글(ㄱㄴㄷ~순) 순서 Custom Comparator로 String 정렬
으어으어
2023. 1. 28. 18:01
해당 util은 아래 블로그를 참조하여 만들었습니다.
이미 잘 만들어진 util에 제가 필요로하는 기능을 위한 추가, 수정만 진행하였습니다.
출처는 아래에서 확인 가능합니다.
한글-영어-특수문자 순 정렬하는 java compare 메서드 만들기
카톡을 보게 되면, 한글 -> 영문 -> 특수문자 순으로 정렬을 합니다. 지난 번 프로젝트 하면서 동일한 요구사항이 있었는데, 생각보다 머리아프더라고요. 그냥 문자열순으로 정렬하면 그 순서가
www.reimaginer.me
저제가 작성한 util은 Compartor의 compare를 override하여 구현했습니다.
특수문자, 한글을 포함하여 정렬하기 위한 Custom Comparator 소스
import java.util.Comparator;
import org.apache.commons.lang3.math.NumberUtils;
public class StringComparator implements Comparator<String> {
/**
* 특수문자 > 숫자(0123순) > 영어(대소문자 구분, 대문자 먼저, abc순) > 한글(ㄱㄴㄷ순) 순서 정렬
* <br>정렬 시 공백은 제외하고 정렬한다.
* <br>해당 util은 reimaginer 블로그를 참조하여 만들어졌습니다.
* <br>블로그 링크는 아래 참조
* @param left - 비교할 첫 문자
* @param right - 비교할 두번째 문자
* @throws NullPointerException – 인수가 null이고 이 비교기가 null 인수를 허용하지 않는 경우
* @throws ClassCastException – 인수의 유형이 이 비교기에 의해 비교되지 않는 경우.
* @return 음수,0,양수
*/
@Override
public int compare(String left, String right) {
left = left.replace(" ", "");
right = right.replace(" ", "");
// 비교 대상문자가 모두 숫자일떄
if (!left.startsWith("0") && !right.startsWith("0")
&& NumberUtils.isParsable(left) && NumberUtils.isParsable(right)) {
return makeSortedByNumber(left, right);
}
// 비교 대상문자가 둘중 하나라도 숫자가 아닐때
int leftLen = left.length();
int rightLen = right.length();
int minLen = Math.min(leftLen, rightLen);
for (int i = 0; i < minLen; ++i) {
char leftChar = left.charAt(i);
char rightChar = right.charAt(i);
if (leftChar != rightChar) {
return makeSortedByNotNumber(leftChar, rightChar);
}
}
return leftLen - rightLen;
}
private int makeSortedByNumber(String left, String right) {
double leftDouble = Double.parseDouble(left);
double rightDouble = Double.parseDouble(right);
if (leftDouble > rightDouble) {
return (int) Math.ceil(leftDouble - rightDouble);
} else {
return (int) Math.ceil(rightDouble - leftDouble) * -1;
}
}
private int makeSortedByNotNumber(char leftChar, char rightChar) {
// 특수문자가 있는 경우
if (isAnyMatchSpecial(leftChar, rightChar)) {
if (isEnglish(leftChar) || isNumber(leftChar) || isKorean(leftChar)) {
return 1;
} else {
return -1;
}
} else {
return leftChar - rightChar;
}
}
private boolean isAnyMatchSpecial(char ch1, char ch2) {
return isEnglishAndSpecial(ch1, ch2)
|| isNumberAndSpecial(ch1, ch2)
|| isKoreanAndSpecial(ch1, ch2);
}
private boolean isKoreanAndSpecial(char ch1, char ch2) {
return (isKorean(ch1) && isSpecial(ch2))
|| (isSpecial(ch1) && isKorean(ch2));
}
private boolean isEnglishAndSpecial(char ch1, char ch2) {
return (isEnglish(ch1) && isSpecial(ch2))
|| (isSpecial(ch1) && isEnglish(ch2));
}
private boolean isNumberAndSpecial(char ch1, char ch2) {
return (isNumber(ch1) && isSpecial(ch2))
|| (isSpecial(ch1) && isNumber(ch2));
}
public boolean isEnglish(char ch) {
return (ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z');
}
public boolean isKorean(char ch) {
return ch >= Integer.parseInt("AC00", 16)
&& ch <= Integer.parseInt("D7A3", 16);
}
public boolean isNumber(char ch) {
return ch >= '0' && ch <= '9';
}
public boolean isSpecial(char ch) {
return (ch >= '!' && ch <= '/') // !"#$%&'()*+,-./
|| (ch >= ':' && ch <= '@') //:;<=>?@
|| (ch >= '[' && ch <= '`') //[\]^_`
|| (ch >= '{' && ch <= '~'); //{|}~
}
}
사용 방법
List<OrderDto> orderDtos = new ArrayList<>();
List<String> testArray = Arrays.asList("1234", "832", "123.123", "832.523",
"한글", "가나다라","hello", "check", "ch_ck", "[중괄호]", "[eng]", "{대괄호}",
"1623", "넘버아님", "/특수/", "832", "가나다라1", "Aad", "Check",
"634.123", "634.31123", "01234", "08561", "<eng>", "^test^",
"&대괄호&", "#shap]", "#java]", "#대괄호}"
);
for (int i = 0; i < testArray.size(); i++) {
OrderDto orderDto = new OrderDto();
orderDto.setNum(i);
orderDto.setName(testArray.get(i));
orderDto.setInfo("testArray index : " + i);
orderDtos.add(orderDto);
}
List<String> orderResult = orderDtos.stream()
.sorted((o1, o2) -> new StringComparator().compare(o1.getName(), o2.getName()))
.map(OrderDto::getName)
.collect(Collectors.toList());
결과
#java], #shap], #대괄호}, &대괄호&, /특수/, <eng>, [eng], [중괄호], ^test^, {대괄호}, 01234, 08561, 123.123, 634.123, 634.31123, 832, 832, 832.523, 1234, 1623, Aad, Check, ch_ck, check, hello, 가나다라, 가나다라1, 넘버아님, 한글