Java
Java 정규식
승모근뭉치
2023. 2. 16. 22:07
프로젝트 내 src 내 javabasic 패키지 내 Regex02.java
package javabasic;
import java.util.regex.Pattern;
public class Regex02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String pass = "{}4 /[].'";
// String pass1 = ""
// + ""
// + ""
// + ""
// + ""
// + ""
// + ""
// + ""
// + "";//엔터를 8번 때렸다.엔터를 8번 때리면 pass1 변수는 문자열 길이가 0인 것을 가리키게 된다.
String pass1 = "\n\n\n\n\n\n\n\n";// LF 8개
// System.out.println("pass1 값 : " + pass1);
String pass2 = " ";// tab 8개
// String pass3 = "\t\t";// tab 2개
String pass3 = " ";// tab 2개
// String pass4 = "\n\n";// line feed 2개
// String pass4 = "\f\f";// form feed 2개
// String pass4 = "\v";// 오류: Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
// 윗줄에서 오류가 난다. \v 는 자바에서 알지 않는 듯 하다.
// String pass4 = "\x0b";// 오류: Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
// 윗줄에서 오류가 난다. \x0b 는 Java 에서 알지 않는 듯 하다.
// String pass4 = "\x0c";// 오류: Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
// 윗줄에서 오류가 난다. \x0c 는 Java 에서 쓰지 않는다.
// String pass4 = "\f";// \f (form feed) 는 Java 에서 쓰지만 \f 와 같은 \x0c 는 Java 에서 쓰지 않는 듯 하다..
// String pass4 = "\u000C";
// 윗줄은 \f (form feed) 으 유니코드 문잣 값 \u000C 를 대조해볼 문자열로 정하였다. 오류가 나지 않는다.
// String pass4 = "\u000B";
// 윗줄은 이스케이프 시퀀스(확장 문자열) \v (세로 탭, 수직 탭) 의 유니코드 문잣 값인 \u000B 이다.
// \v (세로 탭) 의 유니코드 문잣 값을 대입해야 오류가 나지 않는다. 16진숫값으로
// 대입하면 16진숫값이 아닌 문자 하나 하나로 나누어 본다.
String pass4 = "\r\n";
// System.out.println(pass4);
// String pass4 = "\r\n";// Carriage Return 과 line feed 로 공백문자2개
// 유효성 검사
boolean validPass = Pattern.matches("^[A-Z|a-z0-9~`!@#$%^&*()-_+={[}]|\\:;\"'<,>.?/\\s]{8,}$", pass);
// boolean validPass = Pattern.matches("^[A-Z|a-z0-9~`!@#$%^&*()-_+={[}]|\\:;\"'<,>.?/\s]{8,}$", pass);
// 위 한줄에서 오류가 발생한다
// Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
// Java 정규식에서
// \s 는 whitespace(공백) 1개로
// [\t\n\x0b\r\f] 와 동일하다
// [...] 안에 있는 확장 문자열 중에
// \x0b 이 있다. 이것은 수직(vertical tab) 이다.
// \x0b 확장 문자열은 다른 확장 문자열인 \v 와 동일하다.
// \s 는 모든 whitespace(공백) 문자들을 정의하고 있다.
// \x0b 를 쓰면 \v 를 쓰는 것과 같은 결과를 나오게 한다.
// first\x0bseond 라는 문자열을 출력하면
// first
// second
// 위 두줄과 같이 출력되는데 first까지 쓴 후 t 다음 자리에서 커서가 바로 수직으로 밑으로
// 다음줄의 같은 자리로 내려가서 고 부분부터 second 를 출력한다. \n line feed 와
// 같은 그러한 기능을 하는 듯 하다..
// 그런데 왜 \v 라고 쓰지 않고 \x0b 라고 쓰는 것일까?
// \s 에서 whitespace(공백)들을 모아놓은 것을 보면 오직
// \v 만 \x0b 라고 기입되어 있다.
// 보통 Java 에서는 문자열 리터럴(문자그대로의것) 표현을 할 때 오로지
// \n, \r, 그리고 \t 를 사용한다.
// \f 는 거의 사용되지 않기는 하지만 말이다.
// \n, \r, \t, 그리고 \f 외에 모든 확장 문자열들은
// printable ASCII 문자가 아니다.
// 여기서 printable 이라는 것은 말그대로
// 프린트라는 기계에서 프린트(출력)를 할 수 있는 것을 말하는 듯 하다..
// 컴퓨터 모니터로 출력하는 것이 아닌 듯 하다..
// 그래서 \n, \r, \t, 그리고 \f 외에 다른 모든 확장 문자열들이
// 프린트가능한 ASCII 문자가 아니라서
// 대신에 \xhh 표기법을 사용하여 나타내어지게 되는 것이다.
// \xhh 는 hexadecimal 의 앞글자 h 를 두번 쓴다는 것을 나타내는 듯 하다..
// 그래스 \xhh 는 16진법으로 나타낸 표기법을 말하는 듯 하다..
// 참고로 \x0c 는 form feed 라는 확장 문자열이다.
// \x0c 는 프린터를 다음장(다음종이)으로 강제로 이동시키게 한다.
// 개발자는 \x0c 를 \f 로도 표현할 수 있다.
// 즉, \x0c 와 \f 는 같은 것이다.
// 프린터 기계가 아니고 컴퓨터 모니터에서 \v 와 \f 를 쓴다면 다음과 같다.
// 터미널이나 명령창에서 \v (수직탭) 과 \f (form feed) 의 결과는 자주
// 같게 나온다. 즉, 프린터 기계에서는 \v 와 \f 가 다른 결과를 내지만,
// 컴퓨터 화면에서는 \v 와 \f 가 똑같은 것이다.
// \s 는 모든 종류으 whitespace 1개 이다.
// 정규 표현식 기호에서 기억해야 할 것은 백슬래시(\) 가 포함된 기호들이다.
// 정규 표현식에서 백슬래쉬(\) 는 확장 문자로,
// 백슬래쉬(\) 다음에 일반 문자가 오면 특수 문자로 취급하며,
// 백슬래쉬(\) 다음에 특수 문자가 오면 그 특수 문자 자체를 의미한다.
// 정규 표현식으 기호 중에 \w 는 알파벳이나 숫자를 의미한다.
// 그런데 Java 에서 \ (백슬래쉬) 문자 그 자체를 특수 문자로 취급하기 때문에,
// 알파벳이나 숫자를 판별하는 정규식 기호를 작성할 때는
// \\w
// 라고 윗줄로 작성해야만 한다.
// Java 에서 백슬래쉬(\) 와 따옴표는 문자 그 자체만으로는 출력되지 않는 특수 문자라고 한다.
// 따옴표가 문자 그 자체만으로 출력되지 않는 이유는,
// 출력문에서는 첫 쌍따옴표부터 그 다음 쌍따옴표가 나올 때 까지 그 사이에 있는 것들만
// 출력하기 때문에 출력문 중간에 쌍따옴표를 넣게 되면 중간에 넣은 쌍따옴표에서 출력 내용이
// 끝나는 것으로 인식되기 때문이다.
// 따옴표를 출력하고 싶을 때는 \' 나 \" 같이 따옴표 바로 앞에 백슬래쉬(\) 를 써야 한다.
// 마찬가지로 백슬래쉬(\) 문자 자체를 출력하고 싶다면 \\ 로 백슬래쉬(\) 를 두 번 입력해야 한다.
// Java 에서는 출력문에서 백슬래쉬(\) 가 나오는 순간 그 바로 다음 문자를 인식해 백슬래쉬(\) + 그 바로 다음 문자를
// 합한 새로운 확장 문자를 읽어서 그에 따른 행동을 처리하는데, 이를 Escape Sequence 라고 한다고 한다.
// Escape Sequence 에는 여러 특수한 경우가 지정되어있다고 하며
// 지정된 문자가 아닐 경우에 오류가 난다.
// 특수문자 입출력 목록
// 입력문자 출력문자
// \ 오류 발생
// \\ \
// \' '
// \" "
// ( (
// \( 오류 발생
// / /
// \/ 오류 발생
//
// 위를 보면 특히 주목할 것은 괄호인 ( 나 ) 같은 괄호기호나
// 슬래쉬 / 는 \(역슬래쉬) 를 앞에 붙이지 않아도 된다.
//
// \n 줄바꿈(라인 피드)
// \r 줄의 맨 처음으로 (캐리지 리턴)
// \b 커서를 한 문자 앞으로(백스페이스)
// \0 빈 칸(null)
// System.out.println("aaa\0bbb\rc");
// 윗줄 출력 결과는 아랫줄와 같다.
// caa bbb
// \r 이전까지는 aaa bbb 가 출력되다가, \r 로 인해 커서가 줄의 맨 처음으로
// 돌아가고, 맨 앞으 a 에 c 가 덮어서 caa bbb 가 출력된다.
// 그러나 이러한 출력 결과는 Unix 나 Mac OS 에서만 관찰 할 수 있다.
// 왜냐하면 Windows 에서는 line ending 으로 CR(Carriage-Return, \r)
// 과 LF(Line Feed, \n) 를 사용하고 Unix 나 Mac OS 는 LF 만
// 사용하기 때문이다.
// 정규 표현식
// | 또는
// () 그룹, 소괄호 안의 문자를 하나로 인식 Grouping
// [] 문자세트, 문자집합으로 괄호안의 어떤 문자든
// [^] 부정 문자세트, 괄호안의 어떤 문자가 아닐 때
// Quantifiers
// ? 없거나 있거나 zero or one
// * 없거나 무한히 많거나 zero or more
// + 하나 또는 많이 one or more
// {n} n번 반복
// {min,} 최소 min 은 있다
// {min,max} 최소 min 만큼 있고 최대 max 만큼 있을 수 있다.
// 정규 표현식을 쓰는 이유는 if 문 등으로 전화번호, 이메일, 주민등록번호가
// 정상적으로 입력되었는지 검증을 할 것을 작성하려고 하면 가독성도 나빠지고
// 왜냐하면 코드의 길이가 너무 길어지기 때문에 정규 표현식으로 짧고 간단하게
// 쓰는 것이다.
// 정규표현식에서는 \d 나 \w 로 써도 통하지만
// 즉 정규표현식에서는 \d 나 \w 각각 통째로가 특수문자이지 \(역슬래쉬) 자체는
// 정규표현식에서는 특수 문자(확장 문자)가 아니지만
// Java 언어에서는 역슬래쉬(\) 문자 자체를 특수 문자로 취급하기 때문에
// \d(숫자,[0-9]와 동일) 나 \w(알파벳 이나 숫자, 언더바(_) 기호) 로
// 쓰는 부분이 Java 내부에서는 반드시
// \\d 나 \\w 가 되어야 정상적으로 작동한다.
// boolean validPass = Pattern.matches("^[A-Z|a-z0-9~`!@#$%^&*()-_+={[}]|\\:;\"'<,>.?/\s]{8,}$", pass);
// 그래서 위에 쓴 줄에서 오류가 난것이다.
// [] 안에 문자집합에 제일 끝에 \s 라고 쓰면 당연히 정규표현식을 쓰는 사람들은 그것이 모든 공백문자를 나타내는 특수 확장 문자라는 것을 알 수 있지만
// [] 안에 문자세트에 제일 끝에 \s 라고 쓰면 Java 내부에서는 컴파일러가 다르게 해석을 한다. 왜냐하면 Java 내부에서는 역슬래쉬(\) 문자 자체가 특수 확장 문자와 같으니까
// [] 안에 문자셋에 제일 끝에 \s 를 보면 통으로 \s 로 보지 않고 특수문자 \ 하나와 알파벳소문자 s 하나로 따로 본다.
// 그런데 Java 내부에서는 역슬래쉬(\) 문자를 특수 문자로 취급하기 때문에
// 단독으로 쓸 수가 없다 단독으로 쓸 수 없기 때문에 설상 \s 게 묶어서 Java 컴파일러가
// Java 내부에서 \s 요렇게 묶어서 읽는다고 하더라도 요런 \s 것 자체는
// 이스케이프 시퀀스 목록에 아예 등록되어 있지 않는 듯 하다.. 그래서 위에서 \s 요 부분은
// 따로따로 읽어낸다. \ 과 s 으로 따로따로 읽는데 s 는 알파벳 소문자니깐 오류가 안나는데
// \(역슬래쉬) 요놈은 단독으로 쓰면 Java 내부 컴파일러는 바로 오류를 발생시켜서 문제가
// 된 것이다. 그래서 [] 안에 문자셋에 제일 끝에 \s 부분을 \\s 요렇게 바꾸면 오류가 나지 않는다.
// Java 내부에서 출력을 할 때 따옴표 안에 문자열 내용에 같은 종류의 따옴표가 섞여 있는
// 경우에 그 따옴표를 문자열의 끝을 나타내는 기호로 인식하지 않고
// 구분하여 오류를 내지 않고 따옴표도 다 출력시키기 위해
// 역슬래쉬(\) 를 이스케이프 시퀀스로 사용하느라 Java 언어 내부에서는
// 역슬래쉬(\) 자체가 특수 문자가 되어 버리는 것이다.
// 그리고 Java 언어 내부에서는 역슬래쉬(\) 문자를 단독으로 출력하고 싶을 때
// 역슬래쉬(\) 문자 단독으로만 사용해서는 오류가 난다.
// Java 언어 내부에서 역슬래쉬(\) 문자가 단독으로 있는 것을 발견한다면
// 이스케이프 시퀀스를 하는 의미가 없고 특수 문자라서 바로 오류를 내게
// 그렇게 정해져 있다.
// 정규 표현식에서
// . 은 모든 아무 문자 1개에 해당한다.
boolean validPass1 = Pattern.matches("^[A-Z|a-z0-9~`!@#$%^&*()-_+={[}]|\\:;\"'<,>.?/\\s]{8,}$", pass1);
boolean validPass2 = Pattern.matches("^[A-Z|a-z0-9~`!@#$%^&*()-_+={[}]|\\:;\"'<,>.?/\\s]{8,}$", pass2);
boolean validPass3 = Pattern.matches("\\s", pass3);
boolean validPass4 = Pattern.matches("\\s", pass4);
System.out.println("비밀번호 : " + validPass);
System.out.println("비밀번호1 : " + validPass1);
System.out.println("비밀번호2 : " + validPass2);
System.out.println("비밀번호3 : " + validPass3);
System.out.println("비밀번호4 : " + validPass4);
}
}
// Java 프로그램의 모든 문자열 리터럴(문자그대로의것)은 String 클래스으 인스턴스로 구현된다.
// String 객체에 보관하는 문자열은 유니코드로 변형되므로 HTML와 같은 마크업 언어에서 문자를 입출력할 때 문제가 발생한다고 한다.
// StringBuilder 와 StringBuffer 는 문자열 값을 초기화 한 후에 초기화한 변수와 같은 주소에 있는 저장할 변수의 메모리 안에 있는 실제값을 변경할 수 있다.
// CharSequence 는 인터페이스(규격) 이다. 요 인터페이스 (규격) 은 읽기가능한 char 값들의 배열이다.
// 현존하는 CharSequence 인터페이스 (규격) 를 구현한 클래스들은 총 5가지라고 한다.
// CharBuffer, Segment, String, StringBuffer, StringBuilder
// 윗줄의 다섯가지 클래스으 사용의도는 저마다 각각 차이가 있다.
// CharBuffer 는 문자열을 다루려는 의도보다는 문자를 저장하기 위해서 사용한다고 한다. 버퍼이다.
// Segment 는 Swing 에서 다루는 문자를 쓸 때 사용한다고 한다. 사용할 일이 거의 없다.
// StringBuffer 와 StringBuilder 의 기능은 같다.
// StringBuffer 기능은 조금 떨어지지만 스레드에서 안전하며
// StringBuilder 기능은 조금 낫지만 스레드에서 안전하지 않다.
// String 클래스는 값을 변경할 수 없는 불변 상태를 지지한다.
// 그리고 문자열을 변경하려는 시도(새 문자를 추가하거나 하는 어떤 다른 형태로의 변경)를 할 때마다
// new String("...") 이라는 String 클래스으 생성자 메서드로 변경 할 때 마다
// 매번 빠짐없이 새로운 String 클래스의 객체를 만들어서
// 기존의 변수가 새로 만든 String 클래스의 객체 주소를 참조하고 가리키도록 만든다.
// 이는 비효율적이다. 매번 쓸데없는 공간을 만들고 시간도 드는 일이다.
// 만약에 입출력이 빈번히 일어난다면 String 클래스의 객체를 변경할 때 마다 새로운 String 클래스의 객체를
// 다시 생성해서 그 주소를 가리키게 하는 방식은 프로그램에 부하를 준다.
// 그래서 빈번한 입출력을 하는 경우에는 문자열을 불변 상태로 만드는 String 클래스 말고
// 문자열을 가변 상태로 다루는 클래스인 StringBuffer 를 사용해야 한다.
// StringBuffer 는 String 클래스에게만 주어지는 특권인 + 기호로 문자열과 문자열을 붙히는 일을 못한다고 한다.
// 그래서 append() 메서드를 사용한다. 그래서 문자열의 값이 계속 가변 상태로 머무르게 해야 한다면 String 을 선택하면 안되고
// StringBuffer 혹은 StringBuilder 를 골라야 한다.
실행 결과
비밀번호 : true
비밀번호1 : true
비밀번호2 : true
비밀번호3 : false
비밀번호4 : false
수직탭이 모야? (what is the Vertical tab?)
문득 수직탭은 들어 본적은 있는데 머하는데 쓰고, 어떻게 출력이 되는지는 모른다는 깨달음(?)을 얻었다. 검색을 해봐도 이렇다할 결과가 없긴한데... 대충 추려내자면 예전에 리본/도트 프린터
minimonk.net