'개발 이야기/Java'에 해당되는 글 22건

  1. 2007.05.30 | JAVA SE의 정규표현식
  2. 2006.12.19 | [본문스크랩] JAVA FTP 프로그램 

JAVA SE의 정규표현식

개발 이야기/Java | 2007. 5. 30. 10:27
Posted by 시반

정규 expression 또는 regex 지원은 버전 1.4 이후 자바 플랫폼의 일부가 되어 왔다. java.util.regex 패키지에서 발견되는 regex 클래스는 펄 언어가 제공하는 것과 유사한 패턴 매칭을 지원하지만 자바 언어 구문 및 클래스를 사용한다.

 

패키지 전체는 Pattern, MatcherPatternSyntaxException의 3가지 클래스로 제한된다. 버전 1.5에서는 MatchResult 인터페이스가 소개되었다.

 

두 클래스 PatternMatcher를 함께 사용한다.

Pattern 클래스를 사용하여 정규 표현식을 정의한 다음, Matcher 클래스를 사용하여 입력 소스에 대해 패턴을 검사한다. 표현식에서 패턴에 구문 오류가 있으면 예외가 발생한다.

 

두 클래스 모두 구성자를 가지지 않는다. 대신, 정규 표현식을 컴파일하여 패턴을 얻은 다음 반환된 Pattern에게 일부 입력 소스를 기반으로 해당 Matcher를 요청한다.

 

Pattern pattern = Pattern.compile( <regular expression> );
Matcher matcher = pattern.matcher( <input source> );

 

Matcher를 얻었으면 일반적으로 입력 소스를 처리하여 포함된 모든 매칭을 찾는다.

find() 메소드를 사용하여 입력 소스에서 패턴의 매칭을 찾는다. find()에 대한 각 호출은 마지막 호출 위치에서 계속되거나 첫 번째 호출 위치 0에서 계속된다. 그런 다음 매칭되는 항목이 group() 메소드에 의해 반환된다.

 

while (matcher.find()) {
   System.out.printf"Found: \"%s\" from %d to %d.%n",
       matcher.group(), matcher.start(), matcher.end());
}

다음 코드는 기본적인 정규 표현식 프로그램을 보여 주며 사용자가 정규 표현식과 비교 대상 문자열을 입력하도록 메시지를 표시한다.

 

import java.util.regex.*;

public class Regex {

   public static void main(String args[]) {
      Console console = System.console();

      // Get regular expression
      String regex = console.readLine("%nEnter expression: ");
      Pattern pattern = Pattern.compile(regex);

      // Get source
      String source = console.readLine("Enter input source: ");
      Matcher matcher = pattern.matcher(source);

      // Show matches
      while (matcher.find()) {
         System.out.printf("Found: \"%s\" from %d to %d.%n",
             matcher.group(), matcher.start(), matcher.end());
      }
   }
}

그러면 정규 표현식의 모양은 정확하게 어떠한가?

Pattern 클래스는 보다 세부적인 사항을 제공하지만 기본적으로 정규 표현식은 다른 문자 시퀀스와 일치시킬 문자 시퀀스이다.

예를 들어, "Hello, World" 문자열에서 두 개의 L자("ll") 문자열 리터럴 패턴을 찾을 수 있다. 앞의 프로그램은 시작 위치 2와 끝 위치 4에서 "ll" 패턴을 찾을 것이다. 끝 위치는 일치된 문자열 패턴의 끝 이후에 다음 문자의 위치이다.

"ll" 같은 패턴 문자열은 입력 소스에서 문자적으로 위치하는 지점만을 보고하므로 그리 흥미롭지 않다.

정규 표현식 패턴은 특수 메타 문자를 포함할 수 있다. 메타 문자는 정규 표현식에서 강력한 매칭 기능을 제공한다. 정규 표현식에서는 "([{\^-$|]})?*+."의 15문자를 메타 문자로 사용할 수 있다.일부 메타 문자는 문자 그룹을 나타낸다.

예를 들어, 대괄호([ 및 ])를 사용하면 대괄호 안의 문자 중 하나가 텍스트에서 발견되는 경우 매칭이 성공하는 일련의 문자를 지정할 수 있다. 예를 들어, "co[cl]a" 패턴은 coca 및 cola라는 단어와 매칭된다. []는 단일 문자를 매칭하는 데만 사용되므로 cocla는 매칭되지 않는다.

몇 가지 매칭을 해 보고 문제가 없으면 곧 수량자에 대해 자세히 살펴보자.

개별 문자의 매칭 이외에 대괄호 문자([ 및 ])를 사용하여 [j-z]로 지정된 j-z의 문자처럼 일정 범위의 문자를 매칭할 수 있다. 이러한 문자 범위는 "foo[j-z]"처럼 문자열 리터럴과 결합할 수도 있다. 여기서 fool을 찾으면 매칭이 성공하고 food를 찾으면 매칭이 실패한다. ljz 사이의 범위 안에 있지만 d는 그렇지 않기 때문이다.

 ^ 문자를 사용하여 문자열 리터럴 또는 문자 범위의 제외를 나타낼 수도 있다.

"foo[^j-z]" 패턴은 foo로 시작하고 j에서 z 사이의 문자로 끝나지 않는 단어를 찾는다.

따라서 이번에는 food라는 문자열이 매칭에 성공한다.

[a-zA-Z]처럼 여러 범위를 결합하여 a에서 z 사이의 소문자와 대문자를 나타낼 수도 있다.

정규 표현식을 처음 학습할 때는 문자열 리터럴이 유용하지만 정규 표현식에서 대부분의 사람들이 사용하는 보다 일반적인 요소는 미리 정의된 문자 클래스이다.

여기서 메타 문자 .\가 사용된다. 마침표(.)는 임의 문자를 나타내는 데 사용된다.

따라서 정규 표현식 ".oney"는 money 및 honey와 매칭되며 oney로 끝나는 5자의 어느 단어와도 매칭된다.

반면에 \는 다른 문자와 함께 사용되어 전체 문자 집합을 나타낸다.

예를 들어, 숫자 집합을 나타내기 위해 [0-9]를 사용할 수 있지만 \d를 사용할 수도 있다.

숫자가 아닌 문자 집합을 나타내기 위해 [^0-9]를 사용할 수도 있다.

또는 \D의 미리 정의된 문자 클래스 문자열을 사용할 수 있다.

이러한 모든 문자 클래스 문자열은 모두 기억하기가 어려우므로 패턴 클래스에 대한 자바 플랫폼 문서에 정의되어 있다.

 

다음은 미리 정의된 특수 문자 클래스의 하위 집합이다.

* \s -- whitespace
* \S -- non-whitespace
* \w -- word character [a-zA-Z0-9]
* \W -- non-word character
* \p{Punct} -- punctuation
* \p{Lower} -- lowercase [a-z]
* \p{Upper} -- uppercase [A-Z]

 

미리 정의된 문자열과 관련하여 지적해야 할 사항은 즉각 눈에 띄지 않는다.

위의 Regex 프로그램에 이러한 문자열 중 하나를 사용하려면 표시된 대로 입력한다.

\s는 공백과 매칭된다. 하지만 자바 소스 파일에서 정규 표현식을 하드 코딩하려면 \ 문자가 특별하게 취급된다는 것을 기억해야 한다.

소스에서 이 문자열을 다음과 같이 이스케이프해야 한다.

String regexString = "\\s";

여기서 \\는 문자열에서 하나의 백슬래시를 나타낸다.

 

다른 문자열 리터럴을 나타내기 위한 기타 특수 문자열은 다음과 같다.

* \t -- tab
* \n -- newline
* \r -- carriage return
* \xhh -- hex character 0xhh
* \uhhhh -- hex character 0xhhhh

 

수량자는 정규 표현식을 더욱 흥미롭게 만드는데 문자 클래스 같은 기타 표현식과 결합될 때는 특히 그렇다. 예를 들어, a-z에서 3자의 문자열을 매칭하기 위해 "[a-z][a-z][a-z]" 패턴을 사용할 수도 있지만 그럴 필요가 없다. 문자열을 반복하는 대신 패턴 다음에 수량자를 추가하면 된다.

이 예제의 경우, "[a-z][a-z][a-z]"":[a-z]{3}"으로 나타낼 수 있다. 특정 수량에 대해 숫자가 {} 괄호 안에 들어간다.

?, * 또는 + 문자를 사용하여 0번 또는 한 번, 0번 이상, 한 번 이상을 각각 나타낼 수도 있다.

[a-z]? 패턴은 a-z의 문자와 0번 또는 한 번 매칭된다.

[a-z]* 패턴은 a-z의 문자와 0번 이상 매칭된다.

[a-z]+ 패턴은 a-z의 문자와 한 번 이상 매칭된다.

수량자는 주의해서 사용한다. 0번 매칭을 허용하는 수량자에는 특별한 주의를 기울여야 한다.

괄호 기호({})를 수량자로 사용할 때는 범위를 지정해야 한다.

{3}은 정확히 3번을 의미하지만 {3,}은 적어도 3번을 의미한다. 수량자 {3, 5}3번에서 5번까지의 패턴과 매칭된다.

정규 표현식에는 여기서 살펴본 것보다 훨씬 많은 내용이 있다.

특정 상황에 맞는 정규 표현식을 사용하는 것이 중요하다.

앞의 Regex 프로그램을 사용하여 몇 가지 표현식을 시험해 보고 기대했던 결과가 나오는지 확인해 본다.

여러 가지 수량자를 사용하여 각 차이가 어떻게 나오는지 이해할 수 있도록 한다.

일반적으로 수량자는 가능한 매칭에 대해 최대 수의 문자를 포함하려고 한다.

 

정규 표현식에 대한 자세한 내용을 살펴보려면 자바 온라인 자습서의 정규 표현식 편을 참고한다.

또한 패턴 클래스에 대한 내용은 javadoc을 참고한다.

 

[본문스크랩] JAVA FTP 프로그램 

개발 이야기/Java | 2006. 12. 19. 10:51
Posted by 시반

JAVA 로 FTP Client를 만드시려는 분들께 도움이 될만한 자료 같습니다.
발췌:http://blog.empas.com/juxtapose/7388152
//------------------------------------------------
// ftp 프로그램 :  Ftp.java
// 이 프로그램은 ftp 서버에 접속하여 파일을 전송한다.
// 사용법 :  java  Ftp  서버주소
// 사용예 :  java Ftp  netlab.woosong.ac.kr
//------------------------------------------------

// 라이브러리의 이용
import java.net.*;
import java.io.*;

// Ftp 클래스
public class Ftp {
    // 소켓의 준비
    Socket ctrlSocket;//    제어용 소켓
    public PrintWriter ctrlOutput;//  제어 출력용 스트림
    public BufferedReader ctrlInput;//  제어 입력용 스트림

    final int CTRLPORT = 21 ;//   ftp 제어용 포트

    // openConnection  메소드
    // 주소와 포트 번호로부터 소켓을 만들고 제어용 스트림을 작성한다.
    public void openConnection(String host)
        throws IOException,UnknownHostException
    {
        ctrlSocket = new Socket(host, CTRLPORT);
        ctrlOutput = new PrintWriter(ctrlSocket.getOutputStream());
        ctrlInput
          = new BufferedReader(new InputStreamReader(ctrlSocket.getInputStream()));
    }

    // closeConnection  메소드
    // 제어용 소켓을 닫는다.
    public void closeConnection()
        throws IOException
    {
        ctrlSocket.close() ;
    }


    // showMenu 메소드
    // Ftp의 명령 메뉴를 출력한다.
    public void showMenu()
    {
        System.out.println(">Command?") ;
        System.out.print("2 ls") ;
        System.out.print("    3 cd") ;
        System.out.print("    4 get") ;
        System.out.print("    5 put") ;
        System.out.print("    6 ascii") ;
        System.out.print("    7 binary") ;
        System.out.println("    9 quit") ;
    }

    // getCommand 메소드
    // 이용자가 지정한 명령 번호를 읽어 처리한다.
    public String getCommand()
    {
       String buf = "" ;
       BufferedReader lineread
         = new BufferedReader(new InputStreamReader(System.in)) ;
       
       while(buf.length() != 1){// 1 문자의 입력을 받을 때까지 반복한다.
         try{
           buf = lineread.readLine() ;
         }catch(Exception e)
         {
          e.printStackTrace();
          System.exit(1);
         }
       }
       return (buf) ;
     }

    // doLogin 메소드
    // ftp 서버에 로그-인 한다.
    public void doLogin()
    {
       String loginName = "" ;
       String password = "" ;
       BufferedReader lineread
          = new BufferedReader(new InputStreamReader(System.in)) ;

       try{
            System.out.println("로그인 이름을 입력하세요 : ") ;
            loginName = lineread.readLine() ;
            // USER 명령에 의한 로그인
            ctrlOutput.println("USER " + loginName) ;
            ctrlOutput.flush() ;
            // PASS 명령에 의한 패스워드의 입력
            System.out.println("패스워드를 입력하세요 : ") ;
            password = lineread.readLine() ;
            ctrlOutput.println("PASS " + password) ;
            ctrlOutput.flush() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // doQuit 메소드
    // ftp 서버로부터 로그 아웃한다
    public void doQuit()
    {
       try{
            ctrlOutput.println("QUIT ") ;//  QUIT 명령의 송신
            ctrlOutput.flush() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // doCd  메소드
    // 디렉토리를 변경한다.
    public void doCd()
    {
       String dirName = "" ;
       BufferedReader lineread
          = new BufferedReader(new InputStreamReader(System.in)) ;

       try{
            System.out.println("디렉토리 이름을 입력하세요 : ") ;
            dirName = lineread.readLine() ;
            ctrlOutput.println("CWD " + dirName) ;// CWD 명령
            ctrlOutput.flush() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // doLs 메소드
    // 디렉토리 정보를 얻는다.
    public void doLs()
    {
       try{
            int n ;
            byte[] buff = new byte[1024] ;

            // 데이터용 연결(connection)을 만든다.
            Socket dataSocket = dataConnection("LIST") ;
            //  데이터를 읽어 처리하는 스트림을 사용한다.
            BufferedInputStream dataInput
              = new BufferedInputStream(dataSocket.getInputStream()) ;
            //  디렉토리 정보를 읽고 처리한다.
            while((n = dataInput.read(buff)) > 0){
                System.out.write(buff,0,n)  ;
            }
            dataSocket.close() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // dataConnection 메소드
    // 서버와의 데이터 교환용 소켓을 만든다.
    // 또한, 서버에게 port 명령으로 포트를 알린다.
    public Socket dataConnection(String ctrlcmd)
    {
       String cmd = "PORT " ; //PORT 명령으로 송신할 데이터 저장 변수
       int i ;
       Socket dataSocket = null ;//  데이터 전송용 소켓
       try{
             //  자신의 주소를 얻는다.
             byte[] address = InetAddress.getLocalHost().getAddress() ;
             //  적당한 포트 번호의 서버 소켓을 만든다.
             ServerSocket serverDataSocket = new ServerSocket(0,1) ;
             // PORT 명령용의 송신 데이터를 이용한다.
             for(i = 0; i < 4; ++i)
                 cmd = cmd +  (address[i] & 0xff) + "," ;
             cmd = cmd + (((serverDataSocket.getLocalPort()) / 256) & 0xff)
                       + ","
                       + (serverDataSocket.getLocalPort() & 0xff) ;
             // PORT 명령을 제어용 스트림을 통해 전송한다.
             ctrlOutput.println(cmd) ;
             ctrlOutput.flush() ;
             // 처리 대상 명령 (LIST, RETR, STOR)을 서버로 보낸다.
             ctrlOutput.println(ctrlcmd) ;
             ctrlOutput.flush() ;
             // 서버로부터 접속을 받는다.
             dataSocket = serverDataSocket.accept() ;
             serverDataSocket.close() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
       return  dataSocket ;
    }

    // doAscii 메소드
    // 텍스트 전송 모드로 셋팅한다.
    public void doAscii()
    {
       try{
            ctrlOutput.println("TYPE A") ;// A 모드
            ctrlOutput.flush() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // doBinary 메소드
    // 이진 전송 모드로 셋팅한다.
    public void doBinary()
    {
       try{
            ctrlOutput.println("TYPE I") ;// I 모드
            ctrlOutput.flush() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // doGet 메소드
    // 서버상의 파일을 가져온다.
    public void doGet()
    {
       String fileName = "" ;
       BufferedReader lineread
          = new BufferedReader(new InputStreamReader(System.in)) ;

       try{
            int n ;
            byte[] buff = new byte[1024] ;
            // 서버상의 파일의 이름을 지정한다.
            System.out.println("파일 이름을 입력하세요 : ") ;
            fileName = lineread.readLine() ;
            // 클라이언트상에 수신용 파일을 준비한다.
            FileOutputStream outfile =  new FileOutputStream(fileName) ;
            // 파일 전송용 데이터 스트림을 작성한다.
            Socket dataSocket = dataConnection("RETR " + fileName) ;
            BufferedInputStream dataInput
              = new BufferedInputStream(dataSocket.getInputStream()) ;
            // 서버로부터 데이터를 받아 파일로 저장한다.
            while((n = dataInput.read(buff)) > 0){
                outfile.write(buff,0,n) ;
            }
            dataSocket.close() ;
            outfile.close() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }

    // doPut 메소드
    // 서버에 파일을 전송한다.
    public void doPut()
    {
       String fileName = "" ;
       BufferedReader lineread
          = new BufferedReader(new InputStreamReader(System.in)) ;

       try{
            int n ;
            byte[] buff = new byte[1024] ;
            FileInputStream sendfile = null ;

            // 파일 이름을 지정한다.
            System.out.println("파일명을 입력하세요 : ") ;
            fileName = lineread.readLine() ;
            // 클라이언트상의 파일을 읽어 보낼 준비를 한다.
            try{
                sendfile =  new FileInputStream(fileName) ;
            }catch(Exception e){
                System.out.println("&#44594;?&#44541;&#44625;&#44437;&#44423;&#44511;&#44495;&#44455;&#44522;") ;
                return ;
            }

            // 전송용 데이터 스트림을 사용한다.
            Socket dataSocket = dataConnection("STOR " + fileName) ;
            OutputStream outstr =  dataSocket.getOutputStream() ;
            // 파일을 읽어 네트워크를 경유하여 서버로 보낸다.
            while((n = sendfile.read(buff)) > 0){
                outstr.write(buff,0,n) ;
            }
            dataSocket.close() ;
            sendfile.close() ;
       }catch(Exception e)
       {
            e.printStackTrace();
            System.exit(1);
       }
    }


    // execCommand 메소드
    // 명령에 대응하는 각 처리를 호출한다.
    public boolean execCommand(String command)
    {
          boolean cont = true ;

          switch(Integer.parseInt(command)){
          case 2 : //  서버의 디렉토리 표시 처리
              doLs() ;
              break ;
          case 3 : //  서버의 작업 디렉토리 변경 표시
              doCd() ;
              break ;
          case 4 : //  서버로부터의 파일 얻기 처리
              doGet() ;
              break ;
          case 5 : //  서버로 파일 전송 처리
              doPut() ;
              break ;
          case 6 : //  텍스트 전송 모드
              doAscii() ;
              break ;
          case 7 : //  바이너리 전송 모드
              doBinary() ;
              break ;
          case 9 : //  처리 종료
              doQuit() ;
              cont = false ;
              break ;
          default : // 그 이외의 입력 처리
              System.out.println("번호를 선택하세요 : ") ;
          }
          return(cont) ;
    }

    // main_proc 메소드
    // Ftp의 명령 메뉴를 출력하여 해당되는 처리를 호출한다.
    public void main_proc()
        throws IOException
    {
         boolean cont = true ;
        try {
            //  로그인 처리를 한다.
            doLogin() ;
            while(cont){
                //  메뉴를 출력한다.
                showMenu() ;
                //  명령을 받아서 처리한다.
                 cont = execCommand(getCommand()) ;
             }
        }
        catch(Exception e){
            System.err.print(e);
            System.exit(1);
        }
    }

    // getMsgs 메소드
    // 제어 스트림의 수신 슬롯을 개시한다.
    public void getMsgs(){
        try {
            CtrlListen listener = new CtrlListen(ctrlInput) ;
            Thread listenerthread = new Thread(listener) ;
            listenerthread.start() ;
        }catch(Exception e){
            e.printStackTrace() ;
            System.exit(1) ;
        }
    }

    // main 메소드
    // TCP 연결(connection)을 열어서 처리를 개시한다.
    public static void main(String[] arg){
        try {
            Ftp f = null;

            if(arg.length < 1){
              System.out.println("usage: java Ftp <host name>") ;
              return ;
            }
            f = new Ftp();
            f.openConnection(arg[0]); //  제어용 연결의 설정
            f.getMsgs() ;             //  수신 슬롯의 개시
            f.main_proc();            // ftp 처리
            f.closeConnection() ;     //  연결 닫기
            System.exit(0) ;          //  프로그램 종료
        }catch(Exception e){
            e.printStackTrace();
            System.exit(1);
        }
    }
}

// CtrlListen 클래스
class CtrlListen implements Runnable{
        BufferedReader ctrlInput = null ;
        //  constructor 읽고 처리하기 위한 상대방 지정
        public CtrlListen(BufferedReader in){
            ctrlInput = in ;
        }

        public void run(){
            while(true){
                try{ //  
                    System.out.println(ctrlInput.readLine()) ;
                } catch (Exception e){
                    e.printStackTrace() ;
                    System.exit(1) ;
                }
            }
        }
}

 

'개발 이야기 > Java' 카테고리의 다른 글

jxl을 통한 엑셀 저장하기  (0) 2008.01.16
JAVA API Chm파일 다운로드 링크  (0) 2007.12.21
[JBoss 보안] DataSource 패스워드 암호화  (0) 2007.06.26
[java] 예약어 enum  (0) 2007.06.04
JAVA SE의 정규표현식  (0) 2007.05.30
 
블로그 이미지

시반

시반(詩伴)이란 함께 시를 짓는 벗이란 뜻을 가지고 있습니다. 함께 나눌수 있는 그런 공간이길 바라며...

카테고리

분류 전체보기 (233)
개발 이야기 (73)
Java (22)
VoIP (19)
이클립스 (22)
ORM (6)
MINA (4)
WEB2.0 (57)
DB2 (24)
MySQL (6)
오라클 (26)
기타 (44)
취미 (0)
잡담 (2)