Java String reverse (문자열 뒤집기)

자바에서 문자열을 다루며 빈번하게 하는 작업 중 하나가 뒤집기(reverse)이다.

자바에서 문자열을 뒤집을 수 있는 방법 중 몇 가지를 소개한다.

(String 클래스에 reverse() 메서드가 있으면 좋을 텐데 없다.)

 

문자열 뒤집기 예시 :  "abcde" -> "edcba"


1. StringBuilder, StringBuffer 를 이용

reverse() 메소드를 제공하는 StringBuilder/StringBuffer 클래스를 이용한다. 

바꾸고 싶은 문자열을 이용하여 StringBuilder 또는 StringBuffer 객체를 생성 후에 제공되는 reverse() 메서드를 사용한다. 

public class String_Reverse_Practice {
    public static void main(String[] args) {
        String str = "abcde";

        // reverse
        StringBuffer sb = new StringBuffer(str);
        String reversedStr = sb.reverse().toString();

        System.out.println(reversedStr); // edcba
    }
}

StringBuffer에 대한 추가 설명은 기존에 정리한 링크를 남겨둔다.

2020/12/13 - [Dev/JAVA] - StringBuffer(StringBuilder) 클래스 기본 및 사용

 

StringBuffer(StringBuilder) 클래스 기본 및 사용

StringBuffer(StringBuilder) 클래스 기본 및 사용 StringBuffer(StringBuilder) 클래스는 문자열에 대한 많은 편의기능을 제공한다. 그래서 필요에 따라 문자열을 작업할 때 String 객체가 아닌 StringBuffer(Str..

yangbox.tistory.com


2. char[] 로 변환하여 뒤집기

String 문자열을 char배열로 변환 후 역순으로 새로운 char배열에 저장하여 문자열로 변환한다.

좀 돌아가는 느낌이 들지만 참고로 봐둔다.

public class String_Reverse_Practice {
    public static void main(String[] args) {
        String str = "abcde";

        char[] arr = str.toCharArray(); // String -> char[]
        char[] reversedArr = new char[arr.length];
        for(int i=0; i<arr.length; i++){
            reversedArr[arr.length-1-i] = arr[i];
        }

        String reversedStr = new String(reversedArr);
        System.out.println(reversedStr); // edcba
    }
}

 


3. List로 변환 후 Collections.reverse(list) 이용하여 뒤집기

reverse 메소드를 제공하는 Collections 클래스를 이용하기 위해 List<Character> 타입으로 변환 후 뒤집기를 수행한다.

public class String_Reverse_Practice {
    public static void main(String[] args) {
        String str = "abcde";

        char[] arr = str.toCharArray(); // String -> char[]
        List<Character> list = new ArrayList<>();
        for(char each : arr){ // char[] -> List
            list.add(each);
        }

        // reverse
        Collections.reverse(list);

        ListIterator li = list.listIterator();
        while(li.hasNext()){
            System.out.print(li.next()); // edcba
        }
    }
}

 


 

 

StringBuffer(StringBuilder) 클래스 기본 및 사용

StringBuffer(StringBuilder) 클래스는 문자열에 대한 많은 편의기능을 제공한다. 그래서 필요에 따라 문자열을 작업할 때 String 객체가 아닌 StringBuffer(StringBuilder) 객체를 사용경우가 종종 있다.


String과 StringBuffer(StringBuilder)의 차이

String과 StringBuffer(StringBuilder)의 차이점은 일단 String은 고정된 길이의 불변(immutable) 문자열이다.

불변이므로 String 객체를 변경시 실제로 변경되는 것이 아닌 새로운 String 객체를 생성한다. 반면에 StringBuffer와 StringBuilder는 변경이 가능하다.(String 처럼 새로운 객체를 생성하는 것이 아닌 그 객체 자체가 변경된다.)

그러므로 문자열의 변경이 잦은 작업이라면 String 대신 StringBuffer 또는 StringBuilder의 사용을 고려한다.

 

StringBuffer와 StringBuilder의 차이는 멀티스레드 환경에서 thread-safe 여부가 다르다. StringBuffer는 thread-safe 하므로 여러 쓰레드에서 동시에 해당 문자열에 접근한다면 사용을 고려하고, 그렇지 않다면 StringBuilder를 사용하는 것이 성능에 더 유리하다. (성능과 thread-safe는 반비례라고 생각하면 된다.)

 

정리하면

1. 문자열 변경이 빈번하지 않는다면 String 사용을 고려

2. 문자열이 빈번하게 변경되면서 멀티쓰레드 환경이라면 StringBuffer 사용을 고려

3. 문자열이 빈번하게 변경되면서 멀티쓰레드 환경이 아니라면 StringBuilder 사용을 고려


StringBuffer 생성

StringBuffer는 3가지 생성자로 생성할 수 있다. StringBuffer와 StringBuilder는 사용법이 대동소이 하므로 아래부터는 StringBuffer를 대표로 정리한다.

 

1. 기본 생성자

StringBuffer sb = new StringBuffer();

 

2. int size 값을 인자로 하는 생성자 : int 타입의 값으로 buffer의 사이즈(capacity)를 지정한다. 

StringBuffer sb = new StringBuffer(20);

 

3. String 문자열을 인자로 하는 생성자 : 제일 많이 사용하는 생성자

StringBuffer sb = new StringBuffer("Yangs");

StringBuffer 메소드

많이 사용되는 메소드를 정리해본다.

 

1. append() : 문자열을 추가하기 위해 사용한다.

최초 빈 문자열로 생성 후 "Yangs" 문자열이 추가되었다. 이 후 "World"는 "Yangs" 문자열 뒤에 추가되어 "YangsWorld"가 된다.

public class StringBuffer_Practice {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        System.out.println("최초 : " + sb.toString()); // 최초 :

        sb.append("Yangs");
        System.out.println("append 후 : " + sb.toString()); // append 후 : Yangs
        
        sb.append("World");
        System.out.println("append 후 : " + sb.toString()); // append 후 : YangsWorld
    }
}

 

2. length(), capacity() : StringBuffer의 문자열 길이나 전체 할당된 capacity를 구할 때 사용된다. capacity는 StringBuffer 내부의 문자열을 저장하기 위한 버퍼의 총 갯수로 생각하면 된다. 신경쓰지 않아도 문자열의 길이가 늘어나면 같이 증가한다.

최초 설정된 10의 capacity를 넘어서는 문자열이 append되자 자동으로 capacity가 22로 증가했다.

public class StringBuffer_Practice {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer(10); // 최초 capacity는 10으로 설정
        System.out.println("최초 문자열길이 : " + sb.length() + ", 총 capacity : " + sb.capacity()); // 최초 문자열길이 : 0, 총 capacity : 10

        sb.append("12345678"); // append() 메소드로 문자열을 이어붙힌다.
        System.out.println(sb.toString()); // 12345678
        System.out.println("1. 문자열길이 : " + sb.length() + ", 총 capacity : " + sb.capacity()); // 1. 문자열길이 : 8, 총 capacity : 10

        sb.append("901"); // append() 메소드로 문자열을 이어붙힌다.
        System.out.println(sb.toString()); // 12345678901
        System.out.println("2. 문자열길이 : " + sb.length() + ", 총 capacity : " + sb.capacity()); // 2. 문자열길이 : 11, 총 capacity : 22
    }
}

 

3. insert() : 문자열을 맨 뒤에 삽입하는 append()와 달리 시작 인덱스를 지정하여 원하는 위치에 삽입할 수 있다.

public class StringBuffer_Practice {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Yangs"); // 최초 "Yangs"로 생성
        System.out.println(sb.toString()); // Yangs

        sb.append("World"); // 맨 뒤에 추가
        System.out.println(sb.toString()); // YangsWorld

        sb.insert(5, "Happy"); // 5번째 인덱스에 Happy를 추가(기존 'W' 자리였지만 "Happy"가 추가되면서 밀려났다.)
        System.out.println(sb.toString()); // YangsHappyWorld
    }
}

 

4. reverse() : 문자열을 뒤집을 때 사용한다.

public class StringBuffer_Practice {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Yangs"); // 최초 "Yangs"로 생성
        System.out.println(sb.toString()); // Yangs

        System.out.println("뒤집어 보자 : " + sb.reverse()); // sgnaY
    }
}

 

5. delete(), deleteCharAt() : 인덱스를 지정하여 문자열의 일부분을 삭제하거나 한 문자만 삭제할 때 사용한다.

문자열의 인덱스를 0부터 시작함에 유의한다.

deleteCharAt(int start, int end) 에서 start 인덱스부터 (end-1) 인덱스까지가 삭제됨에 유의한다.

public class StringBuffer_Practice {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("YangsWorld"); // 최초 "YangsWorld"로 생성
        System.out.println(sb.toString()); // YangsWorld

        sb.delete(1,3); // "an" 삭제
        System.out.println(sb.toString()); // YgsWorld

        sb.deleteCharAt(3); // 3번째 인덱스인 'W' 삭제
        System.out.println(sb.toString()); // Ygsorld
    }
}

 

6. replace() : 문자열의 일부분을 다른 문자열로 치환할 수 있다.

문자열의 인덱스는 0부터 시작하며, start 인덱스부터 (end-1) 인덱스까지가 치환됨에 유의한다.

public class StringBuffer_Practice {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("YangsWorld"); // 최초 "YangsWorld"로 생성
        System.out.println(sb.toString()); // YangsWorld

        sb.replace(1,5, "ZZYX"); // "angs"를 "ZZYX"로 치환
        System.out.println(sb.toString()); // YZZYXWorld
    }
}

 


 

String 객체에는 다양한 메소드들이 있는데 한번씩 살펴보고자 한다.

 

1. int length() : 스트링 객체의 문자 갯수에 대해 반환한다.

"Hello".length();  // 5

 

2. Char charAt(int i) : i번째 인덱스에 있는 문자를 반환한다. 예시의 1번째 인덱스는 'e' 이다.(인덱스는 0부터 시작)

"Hello".charAt(1); // e

 

3. String substring(int i) : i번째 인덱스의 문자부터 끝까지를 반환한다.

"Hello".substring(3); // lo

 

4. String substring(int i, int j) : i번째 인덱스부터 j-1번째 인덱스를 반환한다. 1번째 인덱스의 문자는 'e'익고 (3-1)번째 문자는 'l'이다.

"Hello".substring(1,3); // el

 

5. String concat(String str) : 인자의 문자열을 끝에 병합하여 새로운 문자열을 반환한다.

"Hello".concat(" World"); // Hello World

 

6. int indexOf(String s) : 해당문자열이 첫번째로 나타는 인덱스를 반환한다. "Hello"가 처음 나타는 인덱스는 "Hi " 다음 3번째 인덱스이다. 뒤에 한번 더 나타나는 "Hello"는 무시된다.

"Hi Hello World Hello".indexOf("Hello"); // 3

 

7. int indexOf(String s, int i) : 6번과 유사하나 탐색하는 시작 인덱스를 지정한다. 4번째 인덱스부터 찾으므로 뒤에 "Hello"가 시작하는 인덱스인 15를 반환한다. 

"Hi Hello World Hello".indexOf("Hello", 4); // 15

 

8. int lastIndexOf(String s) : 인자의 문자열이 마지막으로 나타나는 인덱스를 반환한다. 마지막으로 나타나느 "Hello"의 시작 인덱스인 15가 반환된다.

"Hi Hello World Hello".lastIndexOf("Hello"); // 15

 

9. boolean equals(Object otherObj) : 인자의 스트링 객체와 동일한지 검증한다. 대소문자를 구분하여 검증한다.

"Hello".equals("hello"); // false

 

10. boolean equalsIgnoreCase(String anotherString) : 9번과 유사하나 대소문자를 구분하지 않고 검증한다.

"Hello".equalsIgnoreCase("hello"); // true

 

11. int compareTo(String anotherString) : 인자의 스트링과 사전상으로 비교한다. 사전상으로 비교한다는 의미는 abc.. 나 ㄱㄴㄷ.. 순으로 오름차순 비교하여 더 앞쪽이면 음수, 같으면 0, 뒷쪽이면 양수가 반환된다.

"Hello" <--> "Zello" 에서는 "H"가 "Z"보다 사전상으로 앞쪽에 위치하므로 음수가 반환됐다.

아래 예시에서는 'H'와 'Z' 또는 'A'와의 차이만큼 정수가 반환되지만 보통 (음수, 0, 양수) 이 정도로만 체크한다.

"Hello".compareTo("Zello"); // -18
"Hello".compareTo("Aello"); // 7
"Hello".compareTo("Hello"); // 0

 

12. int compareToIgnoreCase( String anotherString) : 11번과 유사하지만 비교시 대소문자를 구분하지 않고 비교한다.

"Hello".compareToIgnoreCase("hEllO"); // 0

 

13. String toLowerCase() : 스트링 객체를 소문자로 변경한 새로운 스트링 객체를 반환한다.

"HellO".toLowerCase(); // hello

 

14. String toUpperCase() : 스트링 객체를 대문자로 변경한 새로운 스트링 객체를 반환한다.

"HellO".toUpperCase(); // HELLO

 

16. String replace(char oldChar, char newChar) : 첫번째 인자의 문자를 찾아 두번째 인자로 치환한다.

"Hello".replace('l', 'z'); // hezzo

 


 

 

 

+ Recent posts