문자열 만들기

Java 프로그래밍에서 널리 사용되는 문자열은 문자의 시퀀스입니다. Java 프로그래밍 언어에서 문자열은 객체입니다.

Java 플랫폼은 문자열을 생성하고 조작할 수 있는 String 클래스를 제공합니다.

문자열을 만드는 가장 직접적인 방법은 작성하는 것입니다:

String greeting = "Hello world!";

이 경우 “Hello world!”는 문자열 리터럴(코드에서 큰따옴표로 묶인 일련의 문자)입니다. 컴파일러는 코드에서 문자열 리터럴을 발견할 때마다 해당 값(이 경우 Hello world!)을 가진 String 객체를 생성합니다.

다른 객체와 마찬가지로 new 키워드와 생성자를 사용하여 String 객체를 만들 수 있습니다. String 클래스에는 문자 배열과 같은 다양한 소스를 사용하여 문자열의 초기 값을 제공할 수 있는 13개의 생성자가 있습니다:

char[] helloArray = { 'h', 'e', 'l', 'l', 'o', '.' };
String helloString = new String(helloArray);
System.out.println(helloString);

이 코드 스니펫의 마지막 줄에는 hello가 표시됩니다.

Note: String 클래스는 불변이므로 일단 생성된 String 객체는 변경할 수 없습니다. String 클래스에는 문자열을 수정하는 것으로 보이는 여러 가지 메서드가 있으며, 그 중 일부는 아래에서 설명합니다. 문자열은 불변이므로 이러한 메서드가 실제로 수행하는 작업은 연산 결과를 포함하는 새 문자열을 생성하고 반환하는 것입니다.

 

문자열 길이

객체에 대한 정보를 얻는 데 사용되는 메서드를 접근자 메서드라고 합니다. 문자열에 사용할 수 있는 접근자 메서드 중 하나는 문자열 객체에 포함된 문자 수를 반환하는 length() 메서드입니다. 다음 두 줄의 코드가 실행된 후 len은 17과 같습니다:

String palindrome = "Dot saw I was Tod";
int len = palindrome.length();

팔린드롬(palindrome) 은 대칭인 단어 또는 문장으로, 대소문자와 구두점을 무시하고 앞뒤 철자가 동일합니다. 다음은 팔린드롬 문자열을 반전시키는 짧고 비효율적인 프로그램입니다. 이 프로그램은 0부터 카운트하여 문자열의 th 문자를 반환하는 String 메서드 charAt(i)를 호출합니다.

public class StringDemo {
    public static void main(String[] args) {
        String palindrome = "Dot saw I was Tod";
        int len = palindrome.length();
        char[] tempCharArray = new char[len];
        char[] charArray = new char[len];
        
        // put original string in an 
        // array of chars
        for (int i = 0; i < len; i++) {
            tempCharArray[i] = 
                palindrome.charAt(i);
        } 
        
        // reverse array of chars
        for (int j = 0; j < len; j++) {
            charArray[j] =
                tempCharArray[len - 1 - j];
        }
        
        String reversePalindrome =
            new String(charArray);
        System.out.println(reversePalindrome);
    }
}

프로그램을 실행하면 이 출력이 생성됩니다:

doT saw I was toD

문자열 반전을 수행하기 위해 프로그램은 문자열을 문자 배열로 변환하고(첫 번째 for 루프), 배열을 두 번째 배열로 반전시킨 다음(두 번째 for 루프), 다시 문자열로 변환해야 했습니다. String 클래스에는 문자열 또는 문자열의 일부를 문자 배열로 변환하는 메서드인 getChars()가 포함되어 있으므로 위 프로그램의 첫 번째 for 루프를 다음과 같이 바꿀 수 있습니다.

palindrome.getChars(0, len, tempCharArray, 0);

 

문자열 연결하기

String 클래스에는 두 문자열을 연결하는 메서드가 포함되어 있습니다:

string1.concat(string2); 

이 메서드는 끝에 string2가 추가된 string1인 새 문자열을 반환합니다.

다음과 같이 문자열 리터럴과 함께 concat() 메서드를 사용할 수도 있습니다:

"My name is ".concat("Rumplestiltskin");

문자열은 다음과 같이 + 연산자로 연결되는 것이 더 일반적입니다.

"Hello," + " world" + "!"

그 결과

"Hello, world!"

+ 연산자는 출력문에서 널리 사용됩니다. 예를 들어

String string1 = "saw I was ";
System.out.println("Dot " + string1 + "Tod");

다음을 출력합니다.

Dot saw I was Tod

이러한 연결은 모든 객체가 혼합될 수 있습니다. String이 아닌 각 객체에 대해 해당 객체의 toString() 메서드를 호출하여 String으로 변환합니다.

Note: Java SE 15 이전까지는 Java 프로그래밍 언어에서 리터럴 문자열이 소스 파일의 줄에 걸쳐 있는 것을 허용하지 않으므로 여러 줄 문자열의 각 줄 끝에는 + 연결 연산자를 사용해야 합니다. 예를 들어

String quote = 
    "Now is the time for all good " +
    "men to come to the aid of their country.";

연결 연산자 +를 사용하여 줄 사이를 연결하는 것은 print 문에서 매우 일반적입니다.

Java SE 15부터는 2차원 문자열 리터럴을 작성할 수 있습니다:

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;

 

포맷 문자열 생성하기

형식이 지정된 숫자를 출력하기 위해 printf()format() 메서드를 사용하는 것을 보았습니다. String 클래스에는 PrintStream 객체가 아닌 String 객체를 반환하는 동등한 클래스 메서드인 format()가 있습니다.

String의 정적 format() 메서드를 사용하면 일회성 인쇄 문과 달리 재사용할 수 있는 형식화된 문자열을 생성할 수 있습니다. 예를 들어

System.out.printf("The value of the float " +
                  "variable is %f, while " +
                  "the value of the " + 
                  "integer variable is %d, " +
                  "and the string is %s", 
                  floatVar, intVar, stringVar); 

다음과 같이 쓸 수 있습니다.

String fs;
fs = String.format("The value of the float " +
                   "variable is %f, while " +
                   "the value of the " + 
                   "integer variable is %d, " +
                   " and the string is %s",
                   floatVar, intVar, stringVar);
System.out.println(fs);

 

문자열을 숫자로 변환하기

프로그램에서 숫자 데이터가 문자열 객체(예: 사용자가 입력한 값)로 끝나는 경우가 종종 있습니다.

원시 숫자 타입을 감싸는 Number 서브클래스(Byte, Integer, Double, Float, Long, Short는 각각 문자열을 해당 타입의 객체로 변환하는 valueOf()라는 이름의 클래스 메서드를 제공합니다. 다음은 명령줄에서 두 개의 문자열을 가져와 숫자로 변환하고 값에 대해 산술 연산을 수행하는 ValueOfDemo의 예제입니다:

public class ValueOfDemo {
    public static void main(String[] args) {
 
        // this program requires two 
        // arguments on the command line 
        if (args.length == 2) {
            // convert strings to numbers
            float a = (Float.valueOf(args[0])).floatValue(); 
            float b = (Float.valueOf(args[1])).floatValue();
 
            // do some arithmetic
            System.out.println("a + b = " +
                               (a + b));
            System.out.println("a - b = " +
                               (a - b));
            System.out.println("a * b = " +
                               (a * b));
            System.out.println("a / b = " +
                               (a / b));
            System.out.println("a % b = " +
                               (a % b));
        } else {
            System.out.println("This program " +
                "requires two command-line arguments.");
        }
    }
}

다음은 명령줄 인수에 4.587.2를 사용할 때 프로그램의 출력입니다:

a + b = 91.7
a - b = -82.7
a * b = 392.4
a / b = 0.0516055
a % b = 4.5

Note: 원시 숫자 타입을 래핑하는 Number 서브클래스 각각은 parseXXXX() 메서드도 제공합니다. 예를 들어, parseFloat()는 문자열을 원시 숫자로 변환하는 데 사용할 수 있습니다. 객체 대신 원시 타입이 반환되므로 parseFloat() 메서드가 valueOf() 메서드보다 더 직접적입니다. 예를 들어 ValueOfDemo 프로그램에서 사용할 수 있습니다:

float a = Float.parseFloat(args[0]);
float b = Float.parseFloat(args[1]);

 

숫자를 문자열로 변환하기

값을 문자열 형식으로 작업해야 하기 때문에 숫자를 문자열로 변환해야 하는 경우가 있습니다. 숫자를 문자열로 변환하는 몇 가지 쉬운 방법이 있습니다:

int i;
// Concatenate "i" with an empty string; conversion is handled for you.
String s1 = "" + i;

또는

// The valueOf class method.
String s2 = String.valueOf(i);

Number 서브클래스에는 기본 타입을 문자열로 변환하는 클래스 메서드인 toString()가 포함되어 있습니다. 예를 들어

int i;
double d;
String s3 = Integer.toString(i); 
String s4 = Double.toString(d); 

ToStringDemo 예제는 toString() 메서드를 사용하여 숫자를 문자열로 변환합니다. 그런 다음 프로그램은 몇 가지 문자열 메서드를 사용하여 소수점 앞뒤 자릿수를 계산합니다:

public class ToStringDemo {
    
    public static void main(String[] args) {
        double d = 858.48;
        String s = Double.toString(d);
        
        int dot = s.indexOf('.');
        
        System.out.println(dot + " digits " +
            "before decimal point.");
        System.out.println( (s.length() - dot - 1) +
            " digits after decimal point.");
    }
}

이 프로그램의 출력은 다음과 같습니다:

3 digits before decimal point.
2 digits after decimal point.

 

인덱스로 문자 및 하위 문자열 가져오기

String 클래스에는 문자열의 내용을 검사하고, 문자열 내의 문자 또는 하위 문자열을 찾고, 대소문자를 변경하는 등의 작업을 위한 다양한 메서드가 있습니다.

문자열 내 특정 인덱스에 있는 문자는 charAt() 접근자 메서드를 호출하여 가져올 수 있습니다. 첫 번째 문자의 인덱스는 0이고 마지막 문자의 인덱스는 length() - 1입니다. 예를 들어, 다음 코드는 문자열에서 인덱스 9에 있는 문자를 가져옵니다:

String anotherPalindrome = "Niagara. O roar again!"; 
char aChar = anotherPalindrome.charAt(9);

인덱스는 0부터 시작하므로 다음 그림과 같이 인덱스 9의 문자는 ‘O’입니다:

Char indexes in a string

문자열에서 문자 인덱스 찾기

문자열에서 연속된 문자를 두 개 이상 가져오려면 부분 문자열 메서드를 사용할 수 있습니다. 부분 문자열 메서드에는 두 가지 버전이 있습니다:

  • String substring(int beginIndex, int endIndex): 이 문자열의 부분 문자열인 새 문자열을 반환합니다. 부분 문자열은 지정된 beginIndex에서 시작하여 인덱스 endIndex - 1의 문자까지 확장됩니다.
  • String substring(int beginIndex): 이 문자열의 부분 문자열인 새 문자열을 반환합니다. 정수 인수는 첫 번째 문자의 인덱스를 지정합니다. 여기서 반환된 부분 문자열은 원래 문자열의 끝 부분까지 확장됩니다.

다음 코드는 나이아가라 팔린드롬에서 인덱스 11부터 인덱스 15까지 확장되는 부분 문자열(단어 “roar”는 포함하지 않음)을 가져옵니다:

String anotherPalindrome = "Niagara. O roar again!"; 
String roar = anotherPalindrome.substring(11, 15); 

Extracting characters from a string with substring

하위 문자열을 사용하여 문자열에서 문자 추출하기

문자열을 조작하는 다른 메서드

다음은 문자열을 조작하는 다른 String 메서드 몇 가지입니다:

 

문자열에서 문자 및 하위 문자열 검색하기

다음은 문자열 내에서 문자 또는 하위 문자열을 찾는 다른 String 메서드입니다. String 클래스는 특정 문자 또는 하위 문자열의 문자열 내 위치를 반환하는 접근자 메서드를 제공합니다: indexOf()lastIndexOf(). indexOf() 메서드는 문자열의 시작부터 앞으로 검색하고, lastIndexOf() 메서드는 문자열의 끝부터 뒤로 검색합니다. 문자 또는 하위 문자열을 찾을 수 없는 경우 indexOf()lastIndexOf()는 -1을 반환합니다.

String 클래스는 문자열에 특정 문자 시퀀스가 포함된 경우 true를 반환하는 검색 메서드인 contains도 제공합니다. 문자열에 문자 시퀀스가 포함되어 있다는 것만 알고 싶지만 정확한 위치는 중요하지 않은 경우 이 메서드를 사용합니다.

검색 방법은 다음과 같습니다:

Note: CharSequenceString 클래스에 의해 구현되는 인터페이스입니다. 따라서 contains() 메서드의 인수로 문자열을 사용할 수 있습니다.

 

문자열에 문자 및 하위 문자열 삽입하기

String 클래스에는 문자열에 문자나 하위 문자열을 삽입하는 메서드가 거의 없습니다. 일반적으로 이러한 메서드는 필요하지 않습니다: 문자열에서 제거한 하위 문자열을 삽입하려는 하위 문자열과 연결하여 새 문자열을 만들 수 있습니다.

그러나 String 클래스에는 발견된 문자 또는 하위 문자열을 대체하는 네 가지 메서드가 있습니다. 다음과 같습니다:

 

실제로 작동하는 문자열 클래스

다음 Filename 클래스는 파일 이름의 다른 부분을 분리하기 위해 lastIndexOf()substring()을 사용하는 방법을 보여줍니다.

참고: 다음 Filename 클래스의 메서드는 오류 검사를 수행하지 않으며 인자에 전체 디렉토리 경로와 확장자가 있는 파일 이름이 포함되어 있다고 가정합니다. 이러한 메서드가 프로덕션 코드였다면 인수가 올바르게 구성되었는지 확인했을 것입니다.

public class Filename {
    private String fullPath;
    private char pathSeparator, 
                 extensionSeparator;
 
    public Filename(String str, char sep, char ext) {
        fullPath = str;
        pathSeparator = sep;
        extensionSeparator = ext;
    }
 
    public String extension() {
        int dot = fullPath.lastIndexOf(extensionSeparator);
        return fullPath.substring(dot + 1);
    }
 
    // gets filename without extension
    public String filename() {
        int dot = fullPath.lastIndexOf(extensionSeparator);
        int sep = fullPath.lastIndexOf(pathSeparator);
        return fullPath.substring(sep + 1, dot);
    }
 
    public String path() {
        int sep = fullPath.lastIndexOf(pathSeparator);
        return fullPath.substring(0, sep);
    }
}

다음은 Filename 객체를 구성하고 모든 메서드를 호출하는 프로그램인 FilenameDemo입니다:

public class FilenameDemo {
    public static void main(String[] args) {
        final String FPATH = "/home/user/index.html";
        Filename myHomePage = new Filename(FPATH, '/', '.');
        System.out.println("Extension = " + myHomePage.extension());
        System.out.println("Filename = " + myHomePage.filename());
        System.out.println("Path = " + myHomePage.path());
    }
}

프로그램의 출력은 다음과 같습니다:

Extension = html
Filename = index
Path = /home/user

다음 그림과 같이 확장 메서드는 lastIndexOf()를 사용하여 파일 이름에서 마침표(.)가 마지막으로 나오는 부분을 찾습니다. 그런 다음 lastIndexOf()의 반환값을 사용하여 파일 이름 확장자, 즉 마침표에서 문자열 끝까지의 부분 문자열을 추출합니다. 이 코드는 파일 이름에 마침표가 포함되어 있다고 가정합니다. 파일 이름에 마침표가 없는 경우 lastIndexOf()는 -1을 반환하고, 하위 문자열 메서드는 StringIndexOutOfBoundsException을 던집니다.

또한, 확장 메서드는 substring()의 인자로 점 + 1을 사용합니다. 마침표 문자(.)가 문자열의 마지막 문자인 경우 점 + 1은 문자열의 길이와 같으며, 이는 문자열에서 가장 큰 인덱스보다 하나 더 큽니다(인덱스는 0에서 시작하므로). 이 메서드는 문자열 길이와 같지만 그보다 크지 않은 인덱스를 허용하고 “문자열의 끝”을 의미하는 것으로 해석하기 때문에 substring()의 합법적인 인수가 됩니다.

 

문자열과 문자열의 일부 비교하기

String 클래스에는 문자열과 문자열의 일부를 비교하는 여러 메서드가 있습니다. 다음 표에는 이러한 메서드가 나열되어 있습니다.

다음 프로그램인 RegionMatchesDemoregionMatches() 메서드를 사용하여 다른 문자열 내에서 문자열을 검색하는 프로그램입니다:

public class RegionMatchesDemo {
    public static void main(String[] args) {
        String searchMe = "Green Eggs and Ham";
        String findMe = "Eggs";
        int searchMeLength = searchMe.length();
        int findMeLength = findMe.length();
        boolean foundIt = false;
        for (int i = 0; 
             i <= (searchMeLength - findMeLength);
             i++) {
           if (searchMe.regionMatches(i, findMe, 0, findMeLength)) {
              foundIt = true;
              System.out.println(searchMe.substring(i, i + findMeLength));
              break;
           }
        }
        if (!foundIt)
            System.out.println("No match found.");
    }
}

이 프로그램의 출력은 Eggs입니다.

이 프로그램은 searchMe()가 참조하는 문자열을 한 번에 한 문자씩 단계적으로 살펴봅니다. 각 문자에 대해 프로그램은 regionMatches() 메서드를 호출하여 현재 문자로 시작하는 하위 문자열이 프로그램이 찾고 있는 문자열과 일치하는지 여부를 확인합니다.