20230511

아홍·2023년 5월 11일

2023.05

목록 보기
8/19

JSON : JavaScript Object Notation
데이터 교환을 위한 텍스트 데이터 형식. Key-Value 구성.
문자열로 표기한다.
언어 독립적이다.
Key는 항상 string
https://www.json.org/json-en.html


문자열의 각 단어의 첫 글자를 대문자로 바꿔서 리턴하란다. 공백이 연속될 수도 있어서 나는 split을 사용 안하고, 인덱스로 체크해줬다. 해당 인덱스가 공백이 아니고 바로 앞 인덱스가 공백이거나, 인덱스가 0번인데 공백이 아니면 문자열의 시작으로 체크.
이후 toUpperCase로 첫글자만 substring으로 찢어서 바꿔줬다.

    public static String letterCapitalize(String str) {
        // TODO:
        String ret = str;
        boolean change = false;

        for (int i = 0; i < str.length() - 1; i++) {
            if (str.charAt(0) != ' ') {
                ret = ret.substring(0, 1).toUpperCase() + ret.substring(1);
                change = true;
            }
            if (str.charAt(i) == ' ' && str.charAt(i + 1) != ' ') {
                ret = ret.substring(0, i + 1) + ret.substring(i + 1, i + 2).toUpperCase() + ret.substring(i + 2);
                change =true;
            }
        }
        if (change == false) return "";
        return ret;
    }
    

원하는대로 작동은 하는데 마음에 들지 않는다.
뭔가... 뭔가 지저분하고 문제를 보지 않고 내 코드만 본다면 뭘 하려는지 한 눈에 알아보기 쉽지 않다.

그리고 각 단어의 첫글자만 대문자로 바꾼다던가, 문장의 첫 글자만 대문자로 바꾸는 건 많이 사용할 것 같아서 한 번 찾아봤다.

import org.apache.commons.text.WordUtils;

public class Example {
    public static void main(String[] args) {
        String str = "hello world";
        String capitalizedStr = WordUtils.capitalize(str);
        System.out.println(capitalizedStr);//Hello World
    }
}

org.apache.commons.text.WordUtils 클래스에서 제공하는 capitalize()함수가 있다.
음.. 별게 다 있네. 해당 클래스에서 제공하는 다른 메서드도 찾아봤다.

capitalize(str, 구분자) : 구분자를 기준으로 각 단어의 첫글자를 대문자로

initials() 각 단어의 첫글자 추출

swapCase : 알고리즘으로 대소문자를 바꿈

별게 다 있네


String.join(구분자, 문자열 배열) : 알아서 문자열 합쳐주는 것도 있네


stringify 구현 과제가 나와서 해봤다

    if (data instanceof String) {
      return String.format("\"%s\"", data);
    }

String은 ""로 감싸서 리턴해야해서 요렇게

    if (data instanceof Integer) {
      return String.format("%d", data);
    }
    
    if (data instanceof Boolean) {
      return String.format("%b", data);
    }

정수랑 불리언은 그냥 스트링으로
이렇게 할 필요까지는 없었는데 String이랑 통일된 느낌으로?

문제는 해시맵이랑 배열이었음

    if (data instanceof Object[]) {
      String retString = "[";

      for (int i = 0; i < ((Object[]) data).length; i++) {
        retString = retString + stringify(((Object[]) data)[i]);

        if (i != ((Object[]) data).length - 1) {
          retString = retString + ",";
        }
      }
      retString = retString + "]";

      return retString;
    }

일단 배열
문제풀이방식이 상당히 지저분하지만 어찌어찌 풀었다...
배열은 []에 감싸여서, 구분은 ","로, 마지막 요소에는 따옴표 안넣도록 조심하고.

배열의 요소로 String이 올 수도, Integer나 Boolean, null이 올 수도 있다.
이 때 문자열로 만드는 처리는 앞서 구현해놨으니 재귀로 배열 요소요소의 처리를 떠넘겼다.

    if (data instanceof HashMap) {
      Set<?> keys = ((HashMap<?, ?>) data).keySet();
      Iterator<?> iterator = keys.iterator();

      String retString = "{";

      while (iterator.hasNext()) {
        Object dataKey = iterator.next(); //name
        Object dataValue = ((HashMap<?, ?>) data).get(dataKey);
        retString = retString + stringify(dataKey) + ":" + stringify(dataValue);

        if (iterator.hasNext()) retString = retString + ",";
      }
      retString = retString + "}";
      return retString;
    }

해시맵도 배열과 비슷한 방식으로 풀었다.
{}로 감싸고, 구분은 ","로, 마지막에는 안넣고.
Key는 String, Value로는 어떤 것이든 올 수 있기 때문에 처리를 재귀로 맡김

어찌어찌 풀었는데 방식이 맘에 안들어. 뭔가 지저분해.
레퍼런스 코드 찾아보자


    if (data instanceof Object[]) {
      String[] strs = new String[((Object[]) data).length];
      
      for (int i = 0; i < strs.length; i++) {
        strs[i] = stringify(((Object[])data)[i]);
      }
      
      return Arrays.toString(strs).replace(" ", "");
    }

난 배열 만들때 []넣고 "," 넣는다고 똥꼬쇼했는데
배열은 이미 toString이 있지.........
toString으로 문자열 만들기 전에 각 요소들을 재귀함수로 내가 원하는 문자열로 만들어놓고 그걸 toString.
공백은 없으면 안되니까 제거.
아 근데 replace로 제거하면 지우면 안될 공백도 제거한다.
흠.... 페어 분께서 사용하신 StringJoiner를 사용해야겠다.
페어 프로그래밍이 이런게 좋아.
페어 분들은 나는 생각도 못한걸 쓰신다

+해시맵 내 풀이는 우연히 테스트케이스를 통과했을 뿐이다
JSON은 항상 같은 걸 리턴해야하는데 해시맵의 순서는 나는 알지 못할 해시로 처리하니까.. 구현하려면 해시맵에 순서가 있는 LinkedHashMap을 사용하란다.
LinkedHashMap 알게 된 김에 공부해보자


HashMap은 키의 순서가 put한 순서대로가 아닌 자기 마음대로
LinkedHashMap은 키를 입력한 순서대로 보장된다
나머지 사용법은 HashMap과 비슷해보인다.

+순서를 보장한다고 해서 HashMap의 장점인 빠른 검색이 LinkedHashMap에서는 흐려지지 않을까했는데, LinkedHashMap도 검색 속도가 빠르다네.
다만 순서 보장을 위한 추가 저장 공간을 필요로 한다고 한다.


StringJoiner는 구분자 뿐 아니라 무려 prefix, suffix까지 지정 가능하다!

        StringJoiner sj = new StringJoiner(":", "[", "]");

        sj.add("A");
        sj.add("B");
        sj.add("C");

        System.out.println(sj.toString()); //[A:B:C]
        String[] strs = {"That's", "not", "the", "shape", "of", "my", "heart"};

        String str = Arrays.asList(strs).stream()
                .map(el -> el.toString())
                .collect(Collectors.joining(" "));

        System.out.println(str);//That's not the shape of my heart

joining으로 스트림이랑 쓰기도 좋다!


컴퓨터가 음수를 표현하기 위한 방법 : 2의 보수
양수의 비트를 뒤집고 1을 더한다
ex. 4 > 0100
-4 > 4를 뒤집고 (1011) 1을 더한다 (1100) : 1100

실수를 표현하는 방법 : 부동소수점 + 여러 트릭을 사용한 표준방법
아... 실수는 책으로 이해 못하겠다. 이건 더 알아봐야겠어.

0개의 댓글