정규 표현식에서는 괄호 ( )로 하위 표현식을 묶어 캡처 그룹(capturing group)을 만들 수 있습니다. 아래 정규 표현식에서 첫 번째 그룹은 숫자를, 두 번째 그룹은 영문 알파벳을 각각 매칭합니다.
(\d)([A-Za-z])
쉽게 말해, 이 패턴은 입력 문자열에서 "숫자 바로 뒤에 알파벳이 이어지는" 지점과 일치합니다.
치환 문자열에서 $1은 첫 번째 그룹을, $2는 두 번째 그룹을 가리킵니다. 따라서 String 클래스의 replaceAll() 메서드로 위 정규 표현식을 $1 $2(그룹 사이에 공백 포함)로 치환하면, 숫자 뒤에 단어가 오는 모든 지점에서 숫자와 단어 사이에 공백이 자동으로 삽입됩니다.
예제 1: 숫자 → 알파벳 경계에 공백 추가
import java.util.Scanner;
public class SampleTest {
public static void main(String args[]) {
// 사용자로부터 입력 받기
Scanner sc = new Scanner(System.in);
System.out.println("Enter input text: ");
String input = sc.nextLine();
String result = input.replaceAll("(\\d)([A-Za-z])", "$1 $2");
System.out.println(result);
}
}
실행 결과
Enter input text:
21This 23is 56sample 99text
21 This 23 is 56 sample 99 text
예제 2: 순서에 관계없이 숫자·알파벳 경계에 공백 추가
앞선 방식은 "숫자 → 알파벳" 순서만 처리합니다. 반대 경우인 "알파벳 → 숫자"까지 모두 처리하려면, 전방 탐색(lookahead)과 후방 탐색(lookbehind)을 조합한 다음 표현식을 공백으로 치환하면 됩니다.
(?<=[A-Za-z])(?=[0-9])|(?<=[0-9])(?=[A-Za-z])
이 패턴의 동작 원리는 다음과 같습니다.
(?<=[A-Za-z])— 바로 앞 글자가 영문 알파벳인 위치(?=[0-9])— 바로 뒤 글자가 숫자인 위치- 두 조건(또는 그 반대 조건)이 동시에 만족되는 경계 지점만 매칭됩니다. 탐색 어설션은 문자를 소비하지 않으므로 기존 문자는 그대로 유지되고, 경계에만 공백이 삽입됩니다.
예제 코드
import java.util.Scanner;
public class SampleTest {
public static void main(String args[]) {
String regex = "(?<=[A-Za-z])(?=[0-9])|(?<=[0-9])(?=[A-Za-z])";
// 사용자로부터 입력 받기
Scanner sc = new Scanner(System.in);
System.out.println("Enter input text: ");
String input = sc.nextLine();
String result = input.replaceAll(regex, " ");
System.out.println(result);
}
}
실행 결과
Enter input text:
21This23is56sample99text
21 This 23 is 56 sample 99 text