Java Category/Java

[JAVA] String 클래스

ReBugs 2023. 1. 21.

본 게시글은 혼자 공부하는 자바 (저자 : 신용권)의 책과 유튜브 영상을 참고하였고, 개인적으로 정리하는 글임을 알립니다.


String 생성자

소스상에서 문자열 리터럴은 String 객체로 자동 생성되지만, String 클래스의 다양한 생성자를 이용해서 직접 String 객체를 생성할 수도 있다.

어떤 생성자를 이용해서 String 객체를 생성할지는 제공되는 매개값의 타입에 달려있다.


아래는 사용 빈도수가 높은 생성자들이다. 파일의 내용을 읽거나, 네트워크를 통해 받은 데이터는 보통 byte [] 배열이므로 이것을 문자열로 변환하기 위해 사용된다.

//배열 전체를 String 객체로 생성
String str = new String(byte[] bytes);
//지정된 문자셋으로 디코딩
String str = new String(byte[] bytes, String charsetName);

//배열의 offset 인덱스 위치부터 length만큼 String 객체로 생성
String str = new String(byte[] bytes, int offset, int length);
//지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, int offset, int length, String charsetName);

 

바이트 배열을 이용한 인코딩과 디코딩

  • 인코딩 : String -> 바이트 배열
  • 디코딩 : 바이트 배열 -> String

문자셋을 지정하지 않으면 IDE에서 기본으로 설정된 문자셋으로 인코딩 및 디코딩이 된다.

한글 1글자를 UTF-8로 인코딩하면 3바이트가 되고, EUC-KR로 인코딩하면 2바이트가 된다.

따라서 인코딩할 때 사용한 문자셋으로 디코딩을 해야만 한글이 올바르게 복원될 수 있다.

 

아래는 인코딩과 디코딩을 하는 예제이다.

import java.util.Arrays;

public class BytesToStringExample {
	public static void main(String[] args) throws Exception  {
		String data = "자바";
		
		//String -> byte 배열(기본: UTF-8 인코딩)
		byte[] arr1 = data.getBytes();
		//byte[] arr1 = data.getBytes("UTF-8");
		System.out.println("arr1: " + Arrays.toString(arr1));
		
		//byte 배열 -> String(기본: UTF-8 디코딩)
		String str1 = new String(arr1);
		//String str1 = new String(arr1, "UTF-8");
		System.out.println("str1: " + str1);
		
		//String -> byte 배열(EUC-KR 인코딩)
		byte[] arr2 = data.getBytes("EUC-KR");
		System.out.println("arr2: " + Arrays.toString(arr2));
		
		//byte 배열 -> String(기본: UTF-8 디코딩)
		String str2 = new String(arr2, "EUC-KR");
		System.out.println("str2: " + str2);
	}
}
/*
arr1: [-20, -98, -112, -21, -80, -108]
str1: 자바
arr2: [-64, -38, -71, -39]
str2: 자바
*/

 


String 메소드

문자 추출(charAt())

charAt() 메소드는 매개값으로 주어진 인덱스의 문자를 리턴한다.
아래의 코드는 charAt() 메서드를 이용한 주민등록번호상에서 남자인지 여자인지를 구분하는 코드이다.

public class Main{
	public static void main(String[] args) {
		String ssn = "010624-1230123";
		char sex = ssn.charAt(7);
		switch (sex) {
			case '1':
			case '3':
				System.out.println("남자");
				break;
			case '2':
			case '4':
				System.out.println("여자");
				break;
		}
	}
}
/*
남자
*/

문자열 비교(equals(), compareTo())

equals() 메소드는 문자열이 같은지를 비교할 때 쓰는 메소드이다.
문자열을 비교할 때 == 연산자를 쓰면 원치 않는 결과가 나온다.
String객체끼리 ==연산자를 사용하면 주솟값이 같은지를 true 또는 false로 리턴하기 때문이다.

public class Main{
	public static void main(String[] args) {
		String strVar1 = new String("김민수");
		String strVar2 = "김민수";

		if(strVar1 == strVar2) {
			System.out.println("같은 String 객체를 참조");
		} else {
			System.out.println("다른 String 객체를 참조");
		}
		
		if(strVar1.equals(strVar2)) {
			System.out.println("같은 문자열");
		} else {
			System.out.println("다른 문자열");
		}
	}
}
/*
다른 String 객체를 참조
같은 문자열
*/

 

compareTo() 메소드는 인수로 전달받은 문자열과 비교(대소 관계를 판단)하는 메소드이다.

주어진 문자열과 비교 대상 문자열 간의 사전적 순서를 기준으로 비교하며, 결과에 따라 음수, 0, 양수를 반환한다.

  • 반환 값이 음수: 호출된 문자열이 비교 대상 문자열보다 사전적으로 앞에 위치.
  • 반환 값이 0: 두 문자열이 사전적으로 동일.
  • 반환 값이 양수: 호출된 문자열이 비교 대상 문자열보다 사전적으로 뒤에 위치.
public static void main(String[] args) {
    String str1 = "apple";
    String str2 = "banana";
    String str3 = "apple";

    // str1과 str2 비교
    int result1 = str1.compareTo(str2);
    System.out.println("Comparison of str1 and str2: " + result1);

    // str1과 str3 비교
    int result2 = str1.compareTo(str3);
    System.out.println("Comparison of str1 and str3: " + result2);

    // str2과 str1 비교
    int result3 = str2.compareTo(str1);
    System.out.println("Comparison of str2 and str1: " + result3);
}

바이트 배열로 변환(getBytes())

종종 문자열을 바이트 배열로 변환하는 경우가 있다.

예를 들어 네트워크로 문자열을 전송하거나, 문자열을 암호화할 때 문자열을 바이트 배열로 변환하는 경우가 있다.

문자열을 바이트 배열로 변환하는 메소드는 다음 두 가지가 있다.

  1. byte[] bytes = "문자열".getBytes();
  2. byte[] bytes = "문자열".getBytes(Charset charset);

getBytes() 메소드는 시스템의 기본 문자셋으로 인코딩된 바이트 배열을 리턴한다.

만약 특정 문자셋으로 인코딩된 바이트 배열을 얻으려면 두 번째 메소드를 사용하면 된다.

import java.io.UnsupportedEncodingException;
public class Main{
	public static void main(String[] args) {
		String str = "문자열예제";
		
		byte[] bytes1 = str.getBytes(); //인코딩
		System.out.println("bytes1.length: " + bytes1.length);
		String str1 = new String(bytes1); //디코딩
		System.out.println("bytes1->String: " + str1);
		
		try {
			
			byte[] bytes2 = str.getBytes("EUC-KR"); //인코딩
			System.out.println("bytes2.length: " + bytes2.length);
			String str2 = new String(bytes2, "EUC-KR"); //디코딩
			System.out.println("bytes2->String: " + str2);
			
			
			byte[] bytes3 = str.getBytes("UTF-8"); //인코딩
			System.out.println("bytes3.length: " + bytes3.length);
			String str3 = new String(bytes3, "UTF-8"); //디코딩
			System.out.println("bytes3->String: " + str3);		
			
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
}
/*
bytes1.length: 15
bytes1->String: 문자열예제
bytes2.length: 10
bytes2->String: 문자열예제
bytes3.length: 15
bytes3->String: 문자열예제
*/

어떤 문자셋으로 인코딩하느냐에 따라 바이트 배열의 크기가 달라지는데, EUC-KR은 알파벳은 1바이트, 한글은 2바이트로 변환하고, UTF-8은 알파벳은 1바이트, 한글은 3바이트로 변환한다.
getBytes(Charset charset) 메소드는 잘못된 문자셋을 매개값으로 줄 경우, UnsupportedEncodingException이 발생하므로 예외 처리가 필요하다.
바이트 배열을 다시 문자열로 변환(디코딩)할 때에는 어떤 문자셋으로 인코딩 된 바이트 배열이냐에 따라서 디코딩 방법이 다르다.

단순하게 String(byte[] bytes) 생성자를 이용해서 디코딩하면 시스템의 기본 문자셋을 이용한다.
시스템 기본 문자셋과 다른 문자셋으로 인코딩 된 바이트 배열일 경우 아래와 같은 String 생성자를 이용해서 디코딩해야 한다.

String str = new String(byte[] bytes, String charsetName);

 

str.getBytes().length

str.getBytes().length는 문자를 내부적으로 저장하는 배열의 크기, 곧 바이트 단위 크기를 반환한다.
여기서 인코딩 방식은 자바가 내부적으로 데이터를 저장하는 인코딩 방식을 의미한다.
이것을 프로그램 소스코드를 저장하는 인코딩 방식과 혼동하면 안 된다.
public class Main {
    public static void main(String[] args) {
        String str = "abc";
        String str2 = "감자";
        System.out.println("바이트 배열의 길이: " + str.getBytes().length);
        System.out.println("바이트 배열의 길이: " + str2.getBytes().length);
    }
}
//바이트 배열의 길이: 3
//바이트 배열의 길이: 6

문자열 찾기(indexOf(), contains(), lastIndexOf())

indexOf()메소드는 매개값으로 주어진 문자열이 시작되는 인덱스를 리턴한다. 만약 주어진 문자열이 포함되어 있지 않으면 -1을 리턴한다.

public class Main{
	public static void main(String[] args) {
		String str = "이것은 문자열 입니다.";
		System.out.println(str.indexOf("문자열"));
		System.out.println(str.indexOf("가나다라마바사하"));
	}
}
/*
4
-1
*/

위 예제에서 "이것은 문자열 입니다."에서 "문자열"이 시작되는 인덱스인 4가 리턴된 것이다.
"가나다라마바사하"는 "이것은 문자열 입니다."에 포함되어 있지 않기 때문에 -1이 리턴된 것이다.

 

lastIndexOf() 메소드는 매개값으로 주어진 문자열이 끝나는 인덱스를 리턴한다. 만약 주어진 문자열이 포함되어 있지 않으면 -1을 리턴한다.

public static void main(String[] args) {
    String text = "Hello, World! Hello";
    String pattern = "Hello";

    int lastIndex = text.lastIndexOf(pattern);
    System.out.println("마지막으로 발견된 위치: " + lastIndex);

    // 두 번째로 마지막으로 발견된 위치를 찾기
    int secondLastIndex = text.lastIndexOf(pattern, lastIndex - 1);
    System.out.println("두 번째로 마지막으로 발견된 위치: " + secondLastIndex);
}


 
contains()메소드는 매개값으로 주어진 문자열이 있다면 true, 없다면 false를 리턴한다.

public class Main{
	public static void main(String[] args) {
		String str = "이것은 문자열 입니다.";
		System.out.println(str.contains("문자열"));
		System.out.println(str.contains("가나다라마바사하"));
	}
}
/*
true
false
*/

위 예제에서 "이것은 문자열 입니다."에서 "문자열"이 포함되어 있기 떄문에 true가 리턴된 것이다.
"가나다라마바사하"는 "이것은 문자열 입니다."에 포함되어 있지 않기 때문에 false가 리턴된 것이다.


문자열 길이(length())

length()메소드는 문자열의 길이(문자의 수)를 리턴한다.(공백 포함)

public class Main{
	public static void main(String[] args) {
		String str = "이것은 문자열 입니다.";
		System.out.println(str.length());
		
		System.out.println("아무 문자열이나 입력하는 중입니다.".length());
	}
}
/*
12
19
*/

문자열 대치(replace())

replace() 메소드는 첫 번째 매개값인 문자열을 찾아 두 번째 매개값인 문자열로 대치한 새로운 문자열을 생성하고 리턴한다.

String 객체의 문자열은 변경이 불가능한 특성을 갖기 때문에 replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전히 새로운 문자열이다.

public class Main{
	public static void main(String[] args) {
		String oldStr = "이 문자열은 문자열입니다.";
		String newStr = oldStr.replace("문자열", "새로운 문자열");
		System.out.println(oldStr);
		System.out.println(newStr);
	}
}
/*
이 문자열은 문자열입니다.
이 새로운 문자열은 새로운 문자열입니다.
*/

newStr이 참조하는 객체는 oldStr이 참조하는 객체와는 다른 객체이다.


문자열 잘라내기(substring())

substring() 메소드는 주어진 인덱스에서 문자열을 추출한다. 매개값의 수에 따라 두 가지 형태로 사용된다.

  1. substring(int beginIndex)
  2. substring(int beginIndex, int endIndex)

첫 번째는 주어진 인덱스부터 끝까지 문자열을 추출하고, 두 번째는 주어진 시작(포함)과 끝 인덱스(제외) 사이의 문자열을 추출한다.

public class Main{
	public static void main(String[] args) {
		String str = "가나다라마바사하자차카타파하";
		System.out.println(str.substring(0,7));
		System.out.println(str.substring(7));
	}
}
/*
가나다라마바사
하자차카타파하
*/

 
str.substring(7)은 인덱스 7을 포함해서 문자열 끝까지 문자열을 추출한 것이다.
str.substring(0,7)은 인덱스 0(포함) ~ 7(제외) 사이의 문자열을 추출한 것이다.


알파벳 소·대문자 변경(toLowerCase(), toUpperCase())

toLowerCase() 메소드는 문자열을 모두 소문자로 바꾼 새로운 문자열을 생성한 후 리턴한다.
toUpperCase() 메소드는 문자열을 모두 대문자로 바꾼 새로운 문자열을 생성한 후 리턴한다.

public class Main{
	public static void main(String[] args) {
		String str = "Java Programming";
		String lower = str.toLowerCase();
		String upper = str.toUpperCase();
		System.out.println(str);
		System.out.println(lower);
		System.out.println(upper);
		
	}
}
/*
Java Programming
java programming
JAVA PROGRAMMING
*/

문자열 앞뒤 공백 잘라내기(trim())

trim() 메소드는 문자열 앞뒤 공백을 제거한 새로운 문자열을 생성하고 리턴한다.
trim() 메소드는 앞뒤 공백만 제거할 뿐 중간의 공백은 제거하지 않는다.

public class Main{
	public static void main(String[] args) {
		String tel1 ="   02";
		String tel2 ="123     ";
		String tel3 ="   4567    ";
		String tel = tel1.trim() + tel2.trim() + tel3.trim();
		System.out.println(tel);
	}
}
/*
021234567
*/

문자열 변환(valueOf())

valueOf() 메소드는 기본 타입의 값을 문자열로 변환하는 기능을 가지고 있다.
String 클래스에는 매개 변수의 타입별로 valueOf() 메소드가 아래와 같이 오버로딩되어 있다.

static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(double d)
static String valueOf(float f)

 
아래는 실행 예제

public class Main{
	public static void main(String[] args) {
		String str1 = String.valueOf(10);
		String str2 = String.valueOf(10.5);
		String str3 = String.valueOf(true);
		System.out.println(str1);
		System.out.println(str2);
		System.out.println(str3);
	}
}
/*
10
10.5
true
*/

문자열 분리(split())

문자열이 구분자를 사용하여 여러 개의 문자열로 구성되어 있을 경우, 이를 따로 분리해서 얻고 싶다면 split()메소드를 사용한다.

String board = "번호, 제목, 내용, 성명";
String[] arr = board.split(",");

board는 쉼표로 구분된 문자열을 가지고 있다.

split()메소드를 호출할 때 쉼표를 제공하면 분리된 문자열로 구성된 배열을 얻을 수 있다.

public class Main {
    public static void main(String[] args) {
        String board = "1,자바 학습,참조 타입 String을 학습합니다.,홍길동";

        //문자열 분리
        String[] tokens = board.split(",");

        //인덱스별로 읽기
        System.out.println("번호: " + tokens[0]);
        System.out.println("제목: " + tokens[1]);
        System.out.println("내용: " + tokens[2]);
        System.out.println("성명: " + tokens[3]);
        System.out.println();

        //for 문을 이용한 읽기
        for (int i = 0; i < tokens.length; i++) {
            System.out.println(tokens[i]);
        }
    }
}
/*
번호: 1
제목: 자바 학습
내용: 참조 타입 String을 학습합니다.
성명: 홍길동

1
자바 학습
참조 타입 String을 학습합니다.
홍길동
*/

댓글