데이터 개선 현황

개선 전

개선 후

주요 성과

  1. 전체 누락 데이터 감소: 1128건에서 273건으로 75.8% 감소
  2. 누락률 개선: 22.5%에서 5.4%로 17.1%p 개선
  3. 분뇨배출시설 데이터 품질 향상: 1073건에서 197건으로 81.6% 개선
//=============================================================================
//
// 지번주소 파싱
// - 지번주소를 PNU코드로 변환
//
//=============================================================================

public class XParseAddr {

    Connection conn = null;

    //-------------------------------------------------------------------------
    //
    //-------------------------------------------------------------------------

    public XParseAddr(Connection con) {

        this.conn = con;
    }

    /**
     * 주소 파싱 함수
     * @param addr
     * @return String(pnu)
     */
    public String GetPNUFromAddr(String addr)
    {
        if (conn == null)
            return "";

        if (addr.isEmpty())
            return "";

        System.out.println( addr );

        String strPNU = "";

        try {

            // [충청북도 청주시 상당구 용암동 1139번지]
            String[] strTmp = addr.split(" ");

            String strGuName = strTmp[2];
            String strGuCode = "";
            if (strGuName.equals("상당구")) {
                strGuCode = "43111";
            }
            else if (strGuName.equals("서원구")) {
                strGuCode = "43112";
            }
            else if (strGuName.equals("흥덕구")) {
                strGuCode = "43113";
            }
            else if (strGuName.equals("청원구")) {
                strGuCode = "43114";
            }

            if (strGuCode.equals("")) {

                // 지번 없음
                System.out.println("JIBUN Number is not exist: " + addr);
                return "";
            }

            int nSize = strTmp.length;
            for (int n = 0; n < nSize; n++) {
                String strPart = strTmp[n];

                if (strPart.equals("충청북도"))
                    nSize--;
                else if (strPart.equals("청주시"))
                    nSize--;
            }

            // [상당구 용암동 1139번지]
            String[] strA = new String[ nSize ];

            for (int k = 0, nInx = 0; k < strTmp.length; k++) {

                String strPart = strTmp[k];

                if (strPart.equals("충청북도"))
                    continue;
                if (strPart.equals("청주시"))
                    continue;

                int pos = strPart.indexOf("(");
                if (pos > -1)
                    strPart = strPart.substring(0, pos);

                strA[ nInx++ ] = strPart;
            }

            //-----------------------------------------------------------
            // ex)
            // 상당구 용암동 1139번지  --> 상당구 용암동
            // 상당구 가덕면 삼항리 388번지 2호  --> 상당구 가덕면 삼항리
            //-----------------------------------------------------------

            String searchAddr = "";
            int jibun_inx = -1;

            // 충청남도 당진시 고대면 슬항리
            for (int i = 0; i < strA.length; i++) {

                String strPart = strA[i];

                // 외 9필지, 외1, ...
                if (i == strA.length - 1) {
                    int inx = strPart.indexOf("외");
                    if (inx == 0)
                        break;
                }

                if (strPart.equals("산")) {
                    jibun_inx = i;
                    break;
                }

                int inx = strPart.indexOf("산");
                if (inx == 0) {
                    jibun_inx = i;
                    break;
                }

                char ch = strPart.charAt(0);
                if (48 <= ch && ch <= 57) {
                    jibun_inx = i;
                    break;
                }

                searchAddr += " " + strPart;
            }

            searchAddr = searchAddr.trim();

            // 상당구 가덕면 삼항리
            if (jibun_inx == -1) {
                // 지번 없슴
                System.out.println("JIBUN Number is not exist: " + addr);
                return "";
            }

            //
            String strQuery = "";
            String[] strName = searchAddr.split(" ");

            //-----------------------------------------------------------------
            //
            //-----------------------------------------------------------------

            // 상당구
            if (strName.length == 1) {
                ;
            }
            // 상당구 월오동
            else if (strName.length == 2) {
                strQuery = "SELECT EMD_CD FROM TN_TL_SCCO_EMD"
                            + " WHERE EMD_KOR_NM = '" + strName[1] + "' AND EMD_CD LIKE '" + strGuCode + "%'";
            }
            // 상당구 가덕면 삼항리
            else if (strName.length == 3) {
                strQuery = "SELECT EMD_CD, (select substr(LI_CD, 9, 2) FROM TN_TL_SCCO_LI WHERE LI_KOR_NM = '" + strName[2] + "' AND LI_CD LIKE '" + strGuCode + "%') as LI_CD"
                            + " FROM TN_TL_SCCO_EMD"
                            + " WHERE EMD_KOR_NM = '" + strName[1] + "' AND EMD_CD LIKE '" + strGuCode + "%'";
            }
            else
                System.out.println("[QUERY] CHECK SELECT PARAMETER");

            XDBG.Log( strQuery );

            if (strQuery == "")
                return "";

            XDB pDB = new XDB( conn );
            pDB.open(strQuery, 100);
            ResultSet rs = pDB.getReultSet();
            if (rs != null && rs.next()) {

                String pnu_code_hjd = "";
                String pnu_code_ri = "";

                if (strName.length == 2) {
                    pnu_code_hjd = rs.getString(1);
                    pnu_code_ri = "00";
                }
                else if (strName.length == 3) {
                    pnu_code_hjd = rs.getString(1);
                    pnu_code_ri = rs.getString(2);
                }

                strPNU += pnu_code_hjd.trim();
                strPNU += pnu_code_ri.trim();
            }

            pDB.close();

            // 행정동코드 (X)
            if (rs == null) {
                System.out.println( "rs is null : " + strQuery);
                return "";
            }

            // 산 750번지 1호
            String strNum = "";

            String strSanCheck = strA[ jibun_inx ];
            if (strSanCheck.equals("산")) {
                strNum = "2";
                jibun_inx++;
            }
            else {
                strNum = "1";
            }

            if (jibun_inx <= strA.length) {

                //String strPartName = "";

                int n_size = strA.length;
                for (int n = 0; n < n_size; n++) {

                    String strPart = strA[ n ];
                    //if (strPart.equals("161-3,161-4,161-5"))
                    //    strPartName = "";

                    // ex) 서원구 현도면 중척리 42번지 1호,42-2,42
                    //     --> 서원구 현도면 중척리 42번지 1호,
                    int inx = strPart.indexOf(",");
                    if (inx > -1) {
                        n_size = n + 1;
                        break;
                    }
                }

                // ex) 42번지 1호
                String strSearch = "";

                for (int k = jibun_inx; k < n_size; k++) {

                    String strPart = strA[k];

                    // ex) 서원구 현도면 우록리 345번지 외 1필지
                    int inx = strPart.indexOf("외");
                    if (inx == 0)
                        break;

                    inx = strPart.indexOf("번지");
                    if (inx > -1) {
                        strSearch += strPart;
                        continue;
                    }

                    inx = strPart.indexOf("호");
                    if (inx > -1) {
                        strSearch += strPart;

                        // ex) 33번지 3호 687-2,33-1
                        break;
                        //continue;
                    }

                    // ex) 161-3,161-4,161-5
                    inx = strPart.indexOf(",");
                    if (inx > -1) {
                        strSearch += strPart;
                        continue;
                    }

                }

                // ex) [ 42번지 1호, ] --> [ 42번지 1호 ]
                int inx = strSearch.indexOf(",");
                if (inx > -1) {
                    strSearch = strSearch.substring(0, inx);
                }

                strNum += GetJibunString( strSearch );

            }
            else {

                strNum += "00000000";
            }

            strPNU += strNum;

            // Check PNU Code
            boolean isNum = isNumericArray( strPNU );
            if (strPNU.length() > 19 || isNum == false) {
                System.out.println("[LENGTH] " + strPNU.length() + ", " + strPNU + ", " + addr);
                strPNU = "0";
            }
            else {
                System.out.println( strPNU );
            }
        }
        catch (Exception e) {
            System.out.println( e.getMessage() );
        }

        return strPNU;
    }

    /**
     * 주소 파싱 함수
     * @param addr
     * @return String(addr)
     */
    public String GetParsedAddr(String addr)
    {
        String str = addr;
        if(str == null)
            str = "";

        //str="충청북도 청주시 청원구 남문로1가 산 1번지1외3필지";
        //str="충청북도 청주시 청원구 오창읍 학소리 774 등 2필지(775)";

        String strAddress = str;
        strAddress = strAddress.replace("충청북도 청주시 ","");
        strAddress = strAddress.replace("산 ","산");
        strAddress = strAddress.replace("번지 ","-");
        strAddress = strAddress.replace("번지","-");
        strAddress = strAddress.replace("-0","");

        //System.out.println(strAddress);

        try {

            int main_no_idx = -1;

            for(int i = 0; i <= 9; i++)
            {
               int idx = strAddress.indexOf("" + i);
               if(idx > 0 && (main_no_idx < 0 || main_no_idx > idx))
               {
                  //System.out.println("strAddress length="+strAddress.length()+ " idx="+(idx+1) );
                  if(strAddress.length() >= (idx + 1))
                  {
                     int endIdx = idx + 2;

                     if(strAddress.length() == (idx + 1))
                     {
                        endIdx = idx + 1;
                     }

                     String subStr = strAddress.substring(idx, endIdx);

                     if(!subStr.equals(i + "가") &&
                             !subStr.equals(i + "로") &&
                             !subStr.equals(i + "길") &&
                             !subStr.equals(i + "번")) // 행정경계에 숫자가 있는 경우
                     {
                        main_no_idx = idx;
                     }
                     else
                     {
                        int idx2 = strAddress.indexOf("" + i, idx + 1);
                        if(idx2 > 0 && (main_no_idx < 0 || main_no_idx > idx2))
                        {
                           main_no_idx = idx2;
                        }
                     }
                  }
               }
            } // main_no_idx는 본번의 첫번째 숫자 index

            int sub_no_end_idx = main_no_idx;
            char tmp;
            String preTmp = "";

            for(int j = main_no_idx; j < strAddress.length(); j++)
            {
                tmp = strAddress.charAt(j);
                System.out.println("j substring="+tmp);
                if(!('0'<=tmp && '9'>=tmp) && '-' != tmp) // 숫자가 아니고, 하이픈(-)이 아니면
                {
                    if(preTmp.equals("-")) sub_no_end_idx=sub_no_end_idx-1;
                    break;
                }
                else
                {
                    sub_no_end_idx = j;
                }
            }

            str = strAddress.substring(0,sub_no_end_idx + 1);

            //System.out.println(strAddress.substring(0, sub_no_end_idx + 1));

            //System.out.println("main_no_idx=" + main_no_idx);
            //if(main_no_idx < 0) return; // 번지가 없음

            //문자열 끝만 추출
            String last = str.substring(str.length()-1, str.length());
            //끝자리 문자열이 (-) 하이픈 이면 제거
            int inx = last.indexOf("-");
            if (inx > -1){

                str = str.substring(0, str.length()-1);
            }

        }
        catch(Exception e){
            str = null;
            System.err.println( e.getMessage() );
            //문자열 끝만 추출
            /*String last = strAddress.substring(strAddress.length()-1, strAddress.length());
            //끝자리 문자열이 (-) 0 이면 제거
            int inx = last.indexOf("0");
            if (inx > -1){

                str = strAddress.replace("-0","");
            }else{
                str = null;
            }*/
        }

        System.out.println("원본=>"+ addr + "//파싱후=>" + str);

        return str;
    }
    /**
     * 주소 파싱 함수 (도로명만)
     * @param addr
     * @return String(addr)
     */
    public String GetParsedRoadAddr(String addr)
    {
        /*if (conn == null)
            return "";

        if (addr.isEmpty())
            return "";

        String parsedAddr = ""; //반환될 주소값

        int inx1 = addr.indexOf("충청북도 청주시");
        if (inx1 > -1) {
            parsedAddr = addr.replace("충청북도 청주시 ", "");
        }

        int inx2 = parsedAddr.indexOf(" 산 ");
        if (inx2 > -1){
            System.out.println("산 포함");
            parsedAddr = parsedAddr.replace(" 산 ", " 산");
        }

        int inx3 = parsedAddr.indexOf("-0");
        if (inx3 > -1){
            System.out.println("-0 포함");
            parsedAddr = parsedAddr.replace("-0", "");
        }

        int pos1 = parsedAddr.indexOf("번지");
        if (pos1 > -1){
            System.out.println("번지 포함");
            parsedAddr = parsedAddr.replace("번지", "-");
        }

        int inx4 = parsedAddr.indexOf("번지 ");
        if (inx4 > -1){
            System.out.println("번지+공백 포함");
            parsedAddr = parsedAddr.replace("번지 ", "-");
        }

        int inx5 = parsedAddr.indexOf("- ");
        if (inx5 > -1){
            System.out.println("-+공백");
            parsedAddr = parsedAddr.replace("- ", "-");
        }

        int inx6 = parsedAddr.indexOf(" 외 ");
        if (inx6 > -1){
            System.out.println("외 이후제거 ");
            parsedAddr = parsedAddr.substring(0, inx6);
        }

        int inx7 = parsedAddr.indexOf(" 등 ");
        if (inx7 > -1){
            System.out.println("등 이후제거 ");
            parsedAddr = parsedAddr.substring(0, inx7);
        }

        int inx8 = parsedAddr.indexOf(" 및 ");
        if (inx8 > -1){
            System.out.println("및 이후제거 ");
            parsedAddr = parsedAddr.substring(0, inx8);
        }

        int inx9 = parsedAddr.indexOf(" ,");
        if (inx9 > -1){
            System.out.println("콤마 이후제거");
            parsedAddr = parsedAddr.substring(0, inx9);
        }

        int inx10 = parsedAddr.indexOf(",");
        if (inx10 > -1){
            System.out.println("콤마 이후제거");
            parsedAddr = parsedAddr.substring(0, inx10);
        }

        int inx11 = parsedAddr.indexOf("(");
        if (inx11 > -1){
            System.out.println("괄호 이후제거");
            parsedAddr = parsedAddr.substring(0, inx11);
        }

        //뒷자리만 되도록 수정해야함
        int inx12 = parsedAddr.indexOf("호 ");
        if (inx12 > -1){
            System.out.println("호제거");
            parsedAddr = parsedAddr.substring(0, inx12);
        }

        int inx13 = parsedAddr.indexOf("번지외");
        if (inx13 > -1){
            System.out.println("번지외 제거 ");
            parsedAddr = parsedAddr.substring(0, inx13);
        }

        int inx14 = parsedAddr.indexOf("번지외");
        if (inx14 > -1){
            System.out.println("번지외 제거 ");
            parsedAddr = parsedAddr.substring(0, inx14);
        }*/
        //System.out.println(parsedAddr);
        String str = addr;

        if(str == null)
            str="";

        int inx6 = str.indexOf(" 외 ");
        if (inx6 > -1){
            System.out.println("외 이후제거 ");
            str = str.substring(0, inx6);
        }

        int inx7 = str.indexOf(" 등 ");
        if (inx7 > -1){
            System.out.println("등 이후제거 ");
            str = str.substring(0, inx7);
        }

        int inx8 = str.indexOf(" 및 ");
        if (inx8 > -1){
            System.out.println("및 이후제거 ");
            str = str.substring(0, inx8);
        }

        int inx9 = str.indexOf(" ,");
        if (inx9 > -1){
            System.out.println("콤마 이후제거");
            str = str.substring(0, inx9);
        }

        int inx10 = str.indexOf(",");
        if (inx10 > -1){
            System.out.println("콤마 이후제거");
            str = str.substring(0, inx10);
        }

        int inx11 = str.indexOf("(");
        if (inx11 > -1){
            System.out.println("괄호 이후제거");
            str = str.substring(0, inx11);
        }

        return str;
    }
    //---------------------------------------------------------------
    //
    //---------------------------------------------------------------

    String GetJibunString(String strPart) {

        String ret = "";

        // ex) 305-3번지
        int pos = strPart.indexOf("-");
        if (pos > -1) {

            String bunji = strPart.substring(0, pos);
            String ho = strPart.substring(pos + 1);
            int nInx = ho.indexOf("호");
            if (nInx > -1)
                ho = ho.substring(0, nInx);

            nInx = ho.indexOf("번지");
            if (nInx > -1)
                ho = ho.substring(0, nInx);

            ret += Get4LenNumberString( bunji );
            ret += Get4LenNumberString( ho );

            return ret;
        }

        pos = strPart.indexOf("번지");
        if (pos > -1) {

            String bunji = strPart.substring(0, pos);
            String ho = strPart.substring(pos + 2);
            int nInx = ho.indexOf("호");
            if (nInx > -1)
                ho = ho.substring(0, nInx);

            ret += Get4LenNumberString( bunji );
            ret += Get4LenNumberString( ho );

            return ret;
        }
        else {
            String bunji = strPart;
            ret += Get4LenNumberString( bunji );
            ret += "0000";
        }

        return ret;
    }

    //---------------------------------------------------------------
    //
    //---------------------------------------------------------------

    String Get4LenNumberString(String strNumber) {

        String str = "";

        int nLen = strNumber.length();
        for (int i = 0; i < 4 - nLen; i++)
            str += "0";

        str += strNumber;

        return str;
    }

    //---------------------------------------------------------------
    //
    //---------------------------------------------------------------

    boolean isNumericArray(String str) {

        if (str == null || str.isEmpty())
            return false;

        for (char c : str.toCharArray())
            if (c < '0' || c > '9')
                return false;

        return true;
    }
}

추가 : 청주시에 맞춰 ‘구’ 이름을 하드코딩으로 매핑하였지만 이를 외부 설정파일이나 데이터베이스로 관리했으면 훨씬 코드가 깔끔해졌을 아쉬움이 남는다.