[일러스트레이터] ai 파일을 cdr 파일로 변환

[일러스트레이터] ai 파일을 cdr 파일로 변환

ai 확장자는 일러스트레이터 파일이다. cdr 확장자는 코렐 드로우 파일이다. 두 프로그램 다 벡터 기반의 이미지 편집 프로그램이다.

ai 파일을 cdr 파일로 변환하려면, 간단히 ai 확장자 파일을 코렐 드로우에서 열고, cdr 확장자로 저장하면 된다.

그런데, 코렐 드로우에서 ai 파일을 열었을 때 레이어들의 위치가 기존과 다르게 어긋나는 경우가 있다. 이럴 때는 일러스트레이터에서 [다른 이름으로 저장]하여 eps 확장자로 저장한 후, 코렐 드로우에서 열고 cdr로 저장하면 된다.

완벽하게 처리되지는 않는다. 코렐 드로우에서 원하는 크기로 새 이미지를 만든 후, 불러온 이미지를 붙여넣어 조정하는 것도 방법이다.

개인적으로는 코렐 드로우 체험판을 사용했다. 코렐 드로우 체험판 받는 곳 : https://www.corel.com/en/

이상 ai 파일을 cdr 파일로 변환하는 방법이었다.

[일러스트레이터] 연결된 파일을 찾을 수 없습니다 (연결된 파일까지 저장하는 방법)

[일러스트레이터] 연결된 파일을 찾을 수 없습니다 (연결된 파일까지 저장하는 방법)

일러스트레이터에서 이미지를 불러왔을 때, <연결된 파일 “000.jpg”를 찾을 수 없습니다. 다른 파일을 선택하려면 [바꾸기]를, 연결을 변경하지 않고 그대로 두려면 [무시]를 선택하십시오.> 라는 메시지가 뜨는 경우가 있다. (아래 이미지)

◆ 원인

일러스트레이터의 ai 파일은 관련 이미지 파일을 내부에 갖고 있는게 아니라, 링크만 해놓는 것으로 보인다. 따라서 아래 이미지가 나타나는 경우는 (1) 파일 위치가 변경되었거나 (2) 파일이 삭제되었거나 (3) 폴더명이 바뀐 경우 등이 있다.

◆ 해결책 (1) 특정이미지 포함시키기

일러스트레이터는 상단 메뉴의 [파일] – [가져오기] 를 해서 이미지 오브젝트를 추가할 수 있는데, 이후 상단의 [포함] 버튼을 눌러야 한다.


 

◆ 해결책 (2) 모든 이미지 포함시키기 

파일에 들어있는 모든 이미지를 [포함]시키고 싶다면, 아래와 같이 저장할 때 [연결 파일 포함] 항목을 체크하면 된다.

상단 메뉴의 [파일] – [저장] – 저장위치 선택 후 – illustrator 옵션 창의 [연결 파일 포함] 항목 체크 – [확인] 클릭

 

이상 일러스트레이터에서 연결된 파일까지 저장하는 방법이었다.

vcf 확장자 파일 여는 법

vcf 확장자 파일 여는 법

vcf 파일은 스마트폰 주소록 파일이고, 이것을 열어서 엑셀로 변환해주는 프로그램이 공개되어 있다.

얌전한 고양이(mbox32)라는 분이 만드신 프로그램인데, 아래 주소로 들어가면 다운받을 수 있다.

– 개발자 공간 카페 글 : https://cafe.naver.com/mbox32/339

– 얌전한 고양이님 블로그 : http://mbox32.blog.me/50174598956

The superclass “javax.servlet.http.HttpServlet” was not found on the Java Build Path

The superclass “javax.servlet.http.HttpServlet” was not found on the Java Build Path 

 jsp파일 1번째 라인에서 해당 에러나는 경우.

프로젝트 우클릭 -> Build Path -> Configure Build Path… -> Libraries 탭 -> add library -> server runtime -> was 선택 -> 끝

출처: http://multifrontgarden.tistory.com/52 [우리집앞마당]

[JAVA] Source not found / jar has no source attachment

[JAVA] Source not found / jar has no source attachment

이클립스에서 특정 클래스나 메서드가 쓰여진 텍스트 위에서, (1) 단축키 F3키를 누르거나 (2) Ctrl키를 누른채 마우스 클릭하면 해당 클래스 또는 메서드의 내용을 볼 수 있다.

그런데 이 내용이라는게 컴파일된 내용이다보니 원래 소스코드를 보고 싶어질 때가 있다.

만약 그게 남이 만든 jar파일(인터넷에서 구한 jar파일)이라면, 이클립스에 디컴파일러를 설치하면 어느 정도 해결할 수 있다.

(참고 : https://blog.naver.com/bb_/220863234051)

문제는 그게 아니다. 내가 만든 jar를 import했는데, 내용을 볼 수 없는 경우다. 바로 아래와 같이 메시지가  나온다.

The JAR file 파일이_위치한_경로/temp.jar has no source attachment.

 

이런 경우 jar를 만들 때 source code를 동봉해서 jar를 만들어주면 된다.

아래와 같이 jar로 만들고 싶은 프로젝트 위에서 마우스 우클릭 – Export 선택한다.

 

Java 폴더의 JAR file을 선택하고 Next 버튼 클릭한다.

Export Java source files and resources 체크박스를 체크하고 Next 버튼을 누른다.

jar를 새로 import한 후, 이클립스를 재기동하고 나서 해당 jar 내의 클래스 또는 메서드를 Ctrl키 + 마우스 클릭해보면 소스코드 내용을 볼 수 있다.

 

[JAVA] getStackTraceString

[JAVA] getStackTraceString

public String getStackTraceString(Throwable throwable) {
    if (throwable == null) {
        return “null”;
    }

    StackTraceElement[] elems = throwable.getStackTrace();
    if (elems == null || elems.length == 0) {
        return “null”;
    }

    StringBuilder builder = new StringBuilder();
    builder.append(throwable.getClass().getName() + “: “ + throwable.getMessage());

    int elemCount = elems.length;
    for (int i=0; i<elemCount; i++) {
        if (elems[i] != null) {
            builder.append(“\n\tat “ + elems[i].toString());
        }
    }

    return builder.toString();
}

Exception 을 catch할 때 보통 e.printStackTrace(); 식으로 쓰는데, 해당 내용을 스트링으로 리턴받고 싶으면 이 메서드를 사용하면 된다.

아래 스크린샷은 e.printStackTrace(); 를 쓰지 않고 System.err.println(getStackTraceString(e)); 를 사용했을 때 콘솔이다. 보다시피 printStackTrace() 와 똑같이 표시된다.

jsp에서는 아래와 같이 쓰면 된다.

<%!
public String getStackTraceString(Throwable throwable) {
    if (throwable == null) {
        return “null”;
    }

    StackTraceElement[] elems = throwable.getStackTrace();
    if (elems == null || elems.length == 0) {
        return “null”;
    }

    StringBuilder builder = new StringBuilder();
    builder.append(throwable.getClass().getName() + “: “ + throwable.getMessage());

    int elemCount = elems.length;
    for (int i=0; i<elemCount; i++) {
        if (elems[i] != null) {
            builder.append(“<br>\tat “ + elems[i].toString());
        }
    }

    return builder.toString();
}
%>

[MySQL] 윈도우10 MySQL 설치 방법

[MySQL] 윈도우10 MySQL 설치 방법

Windows10 64bit 환경에 MySQL 5.6.39 버전을 설치하는 방법을 소개한다.

1. MySQL Community Server (Archived Versions) 페이지 접속 (http://downloads.mysql.com/archives/community/)

여기서 <커뮤니티 서버>란 개인용 무료버전을 뜻한다.

2. 접속한 페이지에서 Product Version 을 5.6.39 로 선택, Operating System 을 Microsoft Windows 로 선택하고 64bit 버전의 Download 버튼을 클릭하여 다운로드한다. (파일명 : mysql-5.6.39-winx64)

 

3. 적당한 위치에 압축풀어 놓는다. 예를 들면 C:\devtool\mysql-5.6.39-winx64 에 압축해제했다.
(bin 폴더가 C:\devtool\mysql-5.6.39-winx64\bin 에 위치하도록 압축해제)

 

4. 내PC위에서 마우스 우클릭 – [속성] – 좌측 [고급 시스템 설정] 클릭 – [고급] 탭 – 하단의 [환경변수] 버튼 클릭

하단에 위치한 <시스템 변수> 리스트에 <새로 만들기>버튼으로 변수이름 MYSQL_HOME, 변수값 C:\devtool\mysql-5.6.39-winx64 인 환경변수를 만든다.

이어서 Path 항목을 선택 후 <편집> 버튼을 클릭하여 환경변수 편집 윈도우를 띄운다. 여기서 <새로 만들기> 버튼을 클릭하고 %MYSQL_HOME%\bin 을 써넣는다.

 

5. C:\devtool\mysql-5.6.39-winx64 폴더의 <my-default.ini> 를 복사해서 <my.ini> 파일로 붙여넣는다. <my-default.ini> 는 예시파일이고, 실제 사용되는 파일은 <my.ini> 이다.

6. my.init 파일의 내용을 아래와 같이 수정한다.

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html
# *** DO NOT EDIT THIS FILE. It’s a template which will be copied to the
# *** default location during install, and will be replaced if you
# *** upgrade to a newer version of MySQL.

[client]
default-character-set = utf8


[mysqld]
character-set-client-handshake = FALSE
init_connect = “SET collation_connection = utf8_general_ci”
init_connect = “SET NAMES utf8”
character-set-server = utf8
collation-server = utf8_general_ci

# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# These are commonly set, remove the # and set as required.
basedir = C:/devtool/mysql-5.6.39-winx64
datadir = C:/devtool/mysql-5.6.39-winx64/data
port = 3306

# server_id = …..

# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[mysqldump]
default-character-set = utf8


[mysql]
default-character-set = utf8
 

7. cmd에 접근해서 mysqld –initialize-insecure 입력

참고로 –initialize-insecure 옵션은 root 계정을 비밀번호 없이 생성한다.

8. cmd 를 관리자 권한으로 실행한다. 명령 프롬프트(=cmd) 우클릭 – [관리자 권한으로 실행] 클릭하면 된다.

mysqld — install 을 입력한다. 서비스 관리에 추가하겠다는 의미다.

이후 net start mysql 을 입력하면 서비스가 기동된다.

(참고로 추가한 서비스를 다시 제거하려면 mysqld –remove 이며, 종료 명령어는 net stop mysql 이다.)

9. cmd 에서 <mysql>을 입력후 <status> 또는 <show variables like ‘char%’;> 라는 명령어를 쓰면 현재 캐릭터셋 상태를 알 수 있다. UTF8로 되어있으면 무방할 것이다.

* status 를 입력했을 경우

* show variables like ‘char%’; 를 입력했을 경우


 

이상 MySQL 설치방법 및 재기동하는 방법을 마친다.

———-

문제해결 1) 시스템 오류 5이(가) 생겼습니다. 액세스가 거부되었습니다.

명령 프롬프트(cmd)를 관리자 권한으로 실행시켜야 한다.

문제해결 2) MySQL 서비스를 시작할 수 없습니다. 시스템 오류가 발생했습니다. 시스템 오류 1067이(가) 생겼습니다. 프로세스가 예기치 않게 종료되었습니다.

MySQL이 설치되었지만 기동되지 않는 문제. cmd에서 mysqld –install 을 입력하면 현재 MySQL설치된 경로가 나타난다. 경로 자체가 틀린 경우 시스템 오류 1067이 날 수 있다. 참고로 시스템 오류2는 파일 경로 오류이다. (no such file or directory)

실행창(Ctrl+R)에서 regedit 명령어로 레지스트리 편집기를 열고, HKEY_LOCAL_MACHINE -> SYSTEM -> CurrentControlSet -> Services -> MySQL 의 ImagePath 값을 수정한다.

mysqld 의 위치를 적어야 하는데, 예를 들면, C:\devtool\mysql-5.6.39-winx64\bin\mysqld MySQL 로 수정한다.

[JAVA] convert File to Blob

[JAVA] convert File to Blob

자바 java.io.File 객체를 java.sql.Blob 객체로 변환하는 코드.

———-

private Blob convertFileToBlob(File file) throws Exception {
  
    Blob blob = null;
    FileInputStream inputStream = null;
  
    try {
        byte[] byteArray = new byte[(int) file.length()];
        inputStream = new FileInputStream(file);
        inputStream.read(byteArray);
   
        blob = new javax.sql.rowset.serial.SerialBlob(byteArray); 
   
    } catch (Exception e) {
        throw e;
   
    } finally {
        try {
            if (inputStream != null) {
                inputStream.close();
            }


        } catch (Exception e) {

            inputStream = null;


        } finally {
            inputStream = null;
        }
    }
  
    return blob;
}
 

[JAVA] 자바 private 변수 접근하는 방법 (setAccessible / IllegalAccessException)

[JAVA] 자바 private 변수 접근하는 방법 (setAccessible / IllegalAccessException)

자바에서 클래스 내의 private 멤버변수 값을 가져오거나 변경하는 방법이다.

이미 널리 공개된 사실이긴 하지만, 모르는 분들도 있는 것 같아 간략히 적어본다.

사실 코딩하다 보면 필요한 경우가 은근히 많은데, 세부적인 방법을 자꾸 까먹어서 여기 적어둔다.

아참, 객체지향 관점에서 private 변수나 private 메서드를 변경하는 건 캡슐화에 위배된다… 는 논란도 있는데, 논란은 논란이고 우리는 갈길을 가자.

1. 자바 파일 생성 (TestVO.java, MainClass.java)

먼저 TestVO.java [테스트 브이오] 라는 이름의 파일을 아래와 같이 만들자.

public class TestVO { 
    public String userId = “홍길동”;
    private String password = “비밀번호1”;
}

그 흔한 게터/세터도 없는 단촐한 클래스다. 이해를 돕고자 단순하게 만들었다.

이어서, public static void main메서드가 있는 MainClass.java 를 만들자.

2. getDeclaredFields 로 멤버변수의 배열 얻기

자바에는 클래스의 멤버변수를 가져올 수 있는 메서드가 있다. Class.class가 소유한 getDeclaredFields 라는 메서드다.

아래와 같이 getDeclaredFields 메서드를 사용하면 특정 클래스 내의 멤버변수를 전부 가져올 수 있다.

public static void main(String[] args) {  
    TestVO testVO = new TestVO();
    Field[] fieldArray = testVO.getClass().getDeclaredFields();
}

비슷한 메서드로 getFields 라는 것을 사용할 수도 있는데, getFields 메서드는 public 변수만 가져온다. 테스트해보면 알거다.

변수배열 뿐 아니라 메서드배열도 가져올 수 있다. getDeclaredMethods 메서드를 쓰면 된다. 마찬가지로 public 메서드만 가져오는 getMethods 라는 것도 있다.

이제 멤버변수(Field)의 배열을 length 만큼 for문 돌리고, 값을 get하면 세팅이 될까? 그렇지 않다. 아래 스크린샷에서 보듯 IllegalAccessException 에러가 발생하게 된다.

java.lang.IllegalAccessException: Class MainClass can not access a member of class TestVO with modifiers “private”

 

3. setAccessible(true) 사용으로 private 변수값 가져오기/수정하기

참고로 필드의 값을 get하는 코드는,

Object value = 필드객체.get(VO객체); 하면 된다.

여기서는

Object value = fieldArray[i].get(testVO); 이다.

IllegalAccessExceptio 오류가 나지 않도록 하려면 get/set 직전에 필드객체.setAccessible(true); 를 쓰면 된다. 아래 스크린샷처럼 말이다.

set도 마찬가지다. set하는 코드는,

필드객체.set(VO객체, 변경된 값); 하면 되는데, 마찬가지로 세팅 직전에 setAccessible(true) 처리가 필요하다.

아래 스크린샷은 private 변수값을 변경한 후, private 변수값을 조회하는 코드다.


 코드 전문을 남겨둔다.

import java.lang.reflect.Field;

    public class MainClass {

        public static void main(String[] args) {
  
            TestVO testVO = new TestVO();
  
            try {

                // private 변수값 변경하기
                Field[] tempArray = testVO.getClass().getDeclaredFields();
                tempArray[1].setAccessible(true);
                tempArray[1].set(testVO, “변경된비밀번호0”);
                tempArray[1].setAccessible(false);
   
            } catch (Exception e) {
                e.printStackTrace();
            }
  
  
             Field[] fieldArray = testVO.getClass().getDeclaredFields();
  
            if (fieldArray != null && fieldArray.length > 0) {
                int fieldCount = fieldArray.length;
   
                for (int i=0; i<fieldCount; i++) {
    
                    try {
                        String fieldName = fieldArray[i].getName();
         
                        fieldArray[i].setAccessible(true);
                        Object value = fieldArray[i].get(testVO);
                        fieldArray[i].setAccessible(false);
     
                        System.out.println(i + “번째 변수 : [” + fieldName + “] == [” + value + “]”);
     
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
        }
    }
}

인터넷 기본 브라우저 설정

인터넷 기본 브라우저 설정

자꾸 인터넷 기본 브라우저가 엣지로 뜨는 문제가 있었다.

익스플로러 상단 메뉴의 [도구] – [인터넷 옵션] – [프로그램] 탭 선택 – [Internet Explorer를 기본 프로그램으로 설정합니다.] 클릭시

[기본 앱]이라는 창이 떠서 인터넷 브라우저를 선택할 수 있다. 하단 스크린샷 참고.

취향에 따라 크롬으로 설정해도 됨.



 

[메이븐] Received fatal alert: protocol_version 에러

[메이븐] Received fatal alert: protocol_version 에러

[ERROR] Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:2.6: Could not transfer artifact org.apache.maven.plugins:maven-resources-plugin:pom:2.6 from/to central (https://repo.maven.apache.org/maven2): Received fatal alert: protocol_version -> [Help 1]

cmd에서 mvn compile 명령어를 쳤는데 분명히 컴파일되어야 할게 오류가 나면서 안되는거다.

내가 예제를 따라 치다가 오타가 났나 싶어서, (1) 예제 다시 코딩 (2) 깃헙에서 예제 그대로 다운로드 (3) 메이븐 재설치 (4) 자바 모든버전 전부 지우고 재설치 (5) C:\Users\사용자명\.m2 폴더 지우고 재시도, 별별짓 다하다가…

얼마 전까지 잘되던 예제가 왜 안될까 생각했다.

생각해보니 지난번과는 다른 노트북을 사용했다. 이번 노트북은 얇아서 랜선을 꽂을 수가 없었고, 그래서 와이파이를 썼다.

옳거니, 와이파이는 MVN저장소 연결을 막는구나.

“Received fatal alert: protocol_version”이 키워드다 싶어서 검색해보니 웬걸. 뭔가 설치하란다.

cmd 에 mvn -Dhttps.protocols=TLSv1.2 install 명령어 입력하니까 한참을 뭘 설치한다. 그리고 나서 mvn compile 해보니, 잘된다.


거의 2시간 넘게 버린 것 같다. 젠장.

참고 : https://stackoverflow.com/questions/50824789/why-am-i-getting-received-fatal-alert-protocol-version-or-peer-not-authentic

(스택오버플로우 형님들 감사합니다.)

<엑셀VBA 입문 11-2강> 배열(Array)

<엑셀VBA 입문 11-2강> 배열(Array)

<엑셀VBA 입문 11강> 배열 다루기 편이 너무 복잡하고 어렵게 쓰여진 것 같아서 다시 쓴다.

11 다시 2강이다.

VBA 배열을 배우기 위해서는 기본적으로 변수에 대해 알아야 한다.

혹시 변수에 대해 잘 모른다면 아래 글을 읽어보면 된다.

<엑셀VBA 입문 0.1강> 변수 (https://blog.naver.com/bb_/221313471573)

변수란 간단하게 값을 담는 상자라고 보면 된다.
배열이란 여러개의 변수가 연속된 것이다. 영어로는 Array[어레이]라고 한다.
다시 말해 변수가 상자라면, 배열은 상자 여러개를 이어붙여놓은 것이다.

1. 배열의 선언

배열의 선언은 “Dim 배열명(크기)” 라고 쓰면 된다.

ex) Dim arr(5)

예를 들어 Dim arr(5) 는 5칸의 배열을 뜻한다. 변수가 5개 연속되어 있다고 보면 된다.

사이즈가 5인 배열은 인덱스 0번부터 인덱스 4번까지의 공간을 갖게 된다.

즉, arr(0), arr(1), arr(2), arr(3), arr(4) 이렇게 5칸을 가지게 되는 것이다.

따라서 배열의 마지막 칸은 (사이즈 – 1)의 값을 갖는다. 알기 쉽게 Last Index[라스트 인덱스]라고 부르자.

2. 배열의 사용

배열을 만드는 이유는 반복문(for문) 처리에 용이하기 때문이다.

사이즈가 5인 배열이 있다면, 인덱스 0번부터 인덱스 4번까지 for문을 돌면서 데이터를 일괄 처리할 수 있다.

3. 배열의 정렬

공부삼아 배열의 값을 정렬하는 함수를 만들어보자.

네이버 메인페이지에서 신문사 이름을 긁어왔다. 이 단어들을 배열에 넣고, 배열을 가나다순(오름차순)으로 정렬하는 함수다.

소스코드는 아래와 같다.

Sub 매크로1()

‘ 매크로1 매크로

‘ 바로 가기 키: Ctrl+k

Dim arr(9)

arr(0) = “매일경제”
arr(1) = “한국경제”
arr(2) = “서울경제”
arr(3) = “국민일보”
arr(4) = “중앙일보”
arr(5) = “조선일보”
arr(6) = “한겨레”
arr(7) = “경향신문”
arr(8) = “매일경제”

‘정렬 이전 배열 표시한다.
MsgBox (getArrayString(arr))

‘배열 정렬한다.
Call sortArray(arr)

‘정렬 이후 배열 표시한다.
MsgBox (getArrayString(arr))

End Sub

‘sortArray : 배열 정렬하기
Function sortArray(arr)
    Dim cnt
    cnt = getArraySize(arr)
   
    Dim lastIdx
    lastIdx = cnt – 1
   
    Dim tempVal
   
    For i = 0 To lastIdx
        For k = i + 1 To lastIdx
            If checkFrontText(arr(i), arr(k)) Then
                tempVal = arr(i)
                arr(i) = arr(k)
                arr(k) = tempVal
            End If
        Next k
    Next i

End Function

‘getArrayString : 배열 텍스트로 만들기
Function getArrayString(arr)
    Dim cnt
    cnt = getArraySize(arr)
   
    Dim lastIdx
    lastIdx = cnt – 1

    Dim result
    result = “”

    For i = 0 To lastIdx
        result = result & i & ” : ” & arr(i) & Chr(10) & Chr(13)
    Next i
   
    getArrayString = result

End Function

‘checkFrontText : 단어 2개를 비교해서 앞쪽에 위치해야 할 경우 true 리턴
Function checkFrontText(text1, text2)

    Dim len1
    Dim len2
    len1 = Len(text1)
    len2 = Len(text2)
   
    ‘공통 길이를 구한다. 둘 중 짧은 길이가 공통된 길이다.
    Dim commonLen
    If len1 < len2 Then
        commonLen = len1
    Else
        commonLen = len2
    End If
   
   
    ‘공통 길이만큼 글자수를 돌면서
    ‘한 글자라도 다르면 true 또는 false를 리턴한다.
    Dim ch1
    Dim ch2
    For i = 1 To commonLen
        ch1 = Mid(text1, i, 1)
        ch2 = Mid(text2, i, 1)
       
        If ch1 > ch2 Then
            checkFrontText = True
            Exit Function
           
        ElseIf ch1 < ch2 Then
            checkFrontText = False
            Exit Function
        End If
    Next i
   
   
    ‘공통 길이만큼 비교했는데 문자열이 동일하다면, 짧은 문자열이 앞에 오도록 한다.
    If len1 > len2 Then
        checkFrontText = True
        Exit Function
    Else
        checkFrontText = False
        Exit Function
    End If
   
End Function

‘getArraySize : 배열 사이즈 가져오기
Function getArraySize(arr)
    getArraySize = UBound(arr) – LBound(arr)
End Function

4. 과제실습

시간이 허락한다면 추가적으로 과제를 실습해보자.

엑셀에서 특정 영역을 드래그해서 선택한 후, Ctrl + k 키를 누르면 오름차순 정렬되는 함수를 만드시오.

힌트를 주자면 Ctrl+K를 누르면 실행되는 함수의 내용은, 크게 3가지 함수로 나눌 수 있다.

(1-1) 드래그된 영역을 배열로 담는다.

(1-2) 배열을 오름차순 정렬(쏘팅)한다.

(1-3) 드래그된 영역의 셀 값을 수정한다.

이어지는 글 <엑셀VBA 입문 12강> 특정파일 특정시트의 특정셀을 가져오는 매크로 : https://blog.naver.com/bb_/221288948784

이어지는 글 <엑셀VBA 입문 13강> 선택영역 한꺼번에 변경하기(VBA Selection)  : https://blog.naver.com/bb_/221303389424

이어지는 글 <엑셀VBA 입문 14강> On Error 구문의 사용 : https://blog.naver.com/bb_/221329746966

<엑셀VBA 입문 0.1강> 변수

<엑셀VBA 입문 0.1강> 변수

블로그를 읽다가 흥미로운 질문을 봤다.

당장 엑셀 VBA를 이용해서 어떤 웹사이트의 내용을 긁어오거나(파싱), 오토마우스로 다른 어플리케이션을 조작하는 방법을 알고 싶다는 분이 계셨다.

어설프나마 필자는 그런 것을 할 수 있다. 무엇보다 바로 그런 것을 가르쳐주고 싶어서 이 강좌를 쓰고 있다.

하지만 지금은 때가 아니다. 기초를 먼저 쌓아야 한다. 그런 의미에서 아주 기본적인 것을 한 번 짚고 넘어가야 한다는 생각에 이 글을 쓴다.

———-

변수

변수란 무엇인가?

변수는 값을 담는 일종의 상자라고 할 수 있다. 변수를 가장 쉽게 이해할 수 있는 설명이다.

변수의 원래 뜻은 <변하는 값>이라는 뜻이지만, 그냥 값을 담는 상자/그릇이라고 생각하자.

예를 들어 a라는 변수(상자)가 있다고 해보자. 이 상자를 사용하기 위해서는 <선언>이라는게 필요하다.

VBA에서는, 변수를 사용하기 위해서 Dim 이라는 명령어로 변수를 <선언>한다.

예를 들어 a 라는 이름의 변수를 쓰고 싶다면,

Dim a

라고 쓴다.

이를 <변수의 선언>이라고 한다. 사용한다고 알리는 것이다.

(물론 VBA의 변수는 선언하지 않아도 사용 가능하다.

그래도 가급적 모든 변수는 선언해주는게 좋다.)

이 a라는 변수에 0 이라는 값을 담아보자.

a = 0

이라고 쓰면 a라는 상자에 0 이라는 값을 넣는 것이다.

변수명 오른쪽에 붙는 등호(=)는 프로그래밍에서 좌측 화살표(←)로 이해하는 것이 좋다.

변수명=값 은, 곧 변수명←값 과 같다.

변수에 값을 담는 것이다. 이를 <변수의 대입>이라고 부른다.

Dim a

a = 0

이라고 하면 이제 a의 값은 0 이다.

Dim a

Dim b

Dim c

a = 2

b = 3

c = a + b

이라고 하면 c의 값은 어떻게 될까?

5가 된다.

(c = a + b 는 사실상 c ← 2 + 3 이라는 의미이기 때문)

만약

Dim a

a = 10

a = a + 3

이라고 하면 어떨까?

결과적으로 a의 값은 13이 된다.

위에서 언급했듯 등호(=)는 <같다>라는 뜻이기보다 <대입>을 의미한다.

기존 a값인 10 에 3 을 더한 13 이 된다.

VBA 변수는 문자열 결합도 가능하다.

문자열 결합은 앤드<&>기호를 사용한다.

이런 식이다.

Dim aa

Dim bb

aa = “문자”

bb = “열”

cc = aa & bb

이 경우 cc의 값은 “문자열”이 된다.

숫자에 문자를 결합할 때도 마찬가지로 앤드<&>기호를 쓴다. 더하기<+>기호는 오직 숫자끼리 더할 때만 사용한다.

Dim a

Dim b

Dim c

Dim d

a = 1

b = “문자열”

c = a & b

d = b & a

c의 값은 “1문자열”이 되고,

d의 값은 “문자열1″이 된다.

정리하면 아래와 같다.

1. VBA 변수의 선언

Dim 변수명

ex) Dim a

2. VBA 변수의 대입

변수명 = 값

ex) a = 100

ex2) b = “문자열”

3. VBA 숫자 변수의 사칙연산

덧셈 : result = a + 5

뺄셈 : result = a – 5

곱셈 : result = a * 5

나누기 : result = a / 5

나머지 구하기 : result = a Mod 5

4. VBA 문자열 변수의 결합

결과변수 = 문자열변수 & 문자열변수

또는

결과변수 = 숫자변수 & 문자열변수

또는

결과변수 = 문자열변수 & 숫자변수

만약 숫자변수 2개 이상을 문자열처럼 결합하고 싶다면

결과변수 = 숫자변수 & “” & 숫자변수

이렇게 쓰면 된다.

ex) c = a & “” & b

<엑셀VBA 입문 13강> 선택영역 한꺼번에 변경하기(VBA Selection)

<엑셀VBA 입문 13강> 선택영역 한꺼번에 변경하기(VBA Selection)

점심에 친구로부터 전화가 걸려왔다. 엑셀 시트에 적힌 숫자들을 모두 -1 시켜야하는데, 그렇게 처리할 파일이 무척 많다고 했다. VBA를 알면 쉽게 끝날 일이지만, 모르면 노가다로 고생할 일이다.

VBA를 모른다길래 단축키를 누르면 셀 값을 -1 시키고 커서를 한줄 아래로 이동시키는 코드를 짜줬다. 조금 써보더니 불편하다고, 드래그해서 선택한 여러 셀의 값을 한번에 고치는 방법은 없느냐고 했다. 물론 있다.

오늘은 선택한 영역의 값을 한꺼번에 수정하는 방법을 알아본다. 무척 유용한 코드가 될 것이다.

1. 함수 추가 (getLeft 함수, getRight 함수, makeRangeText 함수)

우선 아래 3개의 함수를 그대로 갖다 쓰기로 한다. 필자가 직접 짠 코드이고, 그대로 복사해다가 쓰면 된다. getLeft 함수, getRight 함수, makeRangeText 함수 이렇게 3가지이다.

코드는 아래와 같다.

(다 들여다보기엔 많으니 내용은 스킵해도 좋다. 잘 갖다쓰기만 하면 된다.)

‘getLeft : 문자열에서 특정 문자 좌측값을 잘라 가져온다.
‘ex) text가 “ab1cd”이고 mark가 “1”일 경우, “ab”를 리턴한다.
Function getLeft(text, mark)
    ‘대상 텍스트가 빈값일 경우 빈값 리턴
    If Len(text) = 0 Then
        getLeft = “”
        Exit Function
    End If
   
    ‘마크가 빈값일 경우 그대로 리턴
    If Len(mark) = 0 Then
        getLeft = text
        Exit Function
    End If
   
    Dim markIndex
    markIndex = InStr(1, text, mark)
   
    If markIndex > 0 Then
        ‘마크가 존재할 경우 좌측 문자열 리턴
        Dim leftText
        leftText = Mid(text, 1, markIndex – 1)
        getLeft = leftText
        Exit Function
   
    Else
        ‘마크가 존재하지 않을 경우 그대로 리턴
        getLeft = text
        Exit Function
    End If
   
End Function

‘getRight : 문자열에서 특정 문자 우측값을 잘라 가져온다.
‘ex) text가 “ab1cd”이고 mark가 “1”일 경우, “cd”를 리턴한다.
Function getRight(text, mark)
    ‘대상 텍스트가 빈값일 경우 빈값 리턴
    If Len(text) = 0 Then
        getRight = “”
        Exit Function
    End If
   
    ‘마크가 빈값일 경우 그대로 리턴
    If Len(mark) = 0 Then
        getRight = text
        Exit Function
    End If
   
    Dim markIndex
    markIndex = InStr(1, text, mark)
   
    If markIndex > 0 Then
        ‘마크가 존재할 경우 우측 문자열 리턴
        Dim rightText
        rightText = Mid(text, markIndex + Len(mark), Len(text) – markIndex)
        getRight = rightText
        Exit Function
   
    Else
        ‘마크가 존재하지 않을 경우 그대로 리턴
        getRight = text
        Exit Function
    End If
   
End Function

‘makeRangeText : 현재 선택한 셀을 “행값,열값~행값,열값” 형태의 문자열로 리턴한다.
‘ex1) 1개 셀(A1) 선택한 경우 -> “1,1~1,1” 리턴
‘ex2) 1개 셀(G3) 선택한 경우 -> “3,7~3,7” 리턴
‘ex3) n개 셀(G3~I5) 선택한 경우 -> “3,7~5,9” 리턴
Function makeRangeText()
    Dim addr
    addr = Selection.Address
   
    ‘범위에 달러 있는 경우 제거한다
    If InStr(1, addr, “$”) > 0 Then
        addr = Replace(addr, “$”, “”)
    End If

    Dim result

    Dim colonIndex
    colonIndex = InStr(1, addr, “:”)
   
    If colonIndex > 0 Then
        ‘n개 셀 선택(콜론이 있는 경우)
        Dim leftAddr
        Dim rightAddr
        leftAddr = getLeft(addr, “:”)
        rightAddr = getRight(addr, “:”)
       
        result = Range(leftAddr).row & “,” & Range(leftAddr).Column & “~” & Range(rightAddr).row & “,” & Range(rightAddr).Column
    Else
        ‘1개 셀 선택(콜론이 없는 경우)
        result = Range(addr).row & “,” & Range(addr).Column & “~” & Range(addr).row & “,” & Range(addr).Column
    End If

    makeRangeText = result
   
End Function

함수에 관해 간략히 설명하자면 getLeft 함수는 특정 문자열의 좌측값을 가져오는 함수다. 예를 들어 getLeft(“대상문자열”, “문”)이라고 쓰면 리턴값은 “대상”이다.

반면 getRight는 우측값을 가져온다. 예를 들어 getRight(“대상문자열”, “문”)이라고 쓰면 리턴값은 “자열”이다.

마지막으로 makeRangeText 함수는 조금 특이하다. 현재 선택한 범위를 문자열로 리턴해주는데, “행값,열값~행값,열값” 형식으로 리턴한다. 예를 들어서 셀(A1) 1개를 선택한 경우, “1,1~1,1” 이라는 문자열을 리턴한다. 셀(G3~I5) 이렇게 여러 개의 셀을 선택한 경우, “3,7~5,9” 를 리턴한다.

한마디로 셀 1개가 선택되어 있든, 드래그해서 셀 100개가 선택되어 있든 “행값,열값~행값,열값” 형식으로 리턴해준다. 굳이 “A1″을 “1,1”로 바꾸는 이유는, 각 숫자를 이용해서 쉽게 for문을 돌리기 위해서다. 나중에 보게 되겠지만 Cells(행값, 열값).Value 명령어로 특정 셀의 값을 가져올 수 있다. (여기서 행값, 열값은 숫자값이다.)

2. 메인코드 작성 (선택영역의 값을 모두 “1”로 일괄변경)

메인코드는 아래와 같이 작성한다.

Sub 매크로1()

‘ 매크로1 매크로

‘ 바로 가기 키: Ctrl+e


    ‘makeRangeText : 현재 선택한 셀을 “행값,열값~행값,열값” 형태의 문자열로 리턴한다.
    ‘ex) n개 셀(G3~I5) 선택한 경우 -> “3,7~5,9” 리턴
    Dim rangeText
    rangeText = makeRangeText()


    ‘물결(~)을 기준으로 좌측주소값과 우측주소값으로 자른다.
    ‘ex) n개 셀(G3~I5) 선택한 경우 -> leftAddr 은 “3,7” 이 되고, rightAddr 은 “5,9” 가 됨
    Dim leftAddr
    Dim rightAddr
    leftAddr = getLeft(rangeText, “~”)
    rightAddr = getRight(rangeText, “~”)

    ‘쉼표(,)를 기준으로 각 주소값을 행값과 열값으로 자른다.
    ‘ex) n개 셀(G3~I5) 선택한 경우 -> leftRow 은 “3”, leftCol 은 “7”, rightRow 는 “5”, rightCol 은 “9” 가 됨
    Dim leftRow
    Dim leftCol
    Dim rightRow
    Dim rightCol
    leftRow = getLeft(leftAddr, “,”)
    leftCol = getRight(leftAddr, “,”)
    rightRow = getLeft(rightAddr, “,”)
    rightCol = getRight(rightAddr, “,”)

    ‘선택영역의 좌측 상단셀부터 우측 하단셀까지, 반복문을 돌며 각 셀을 처리한다.
    For r = leftRow To rightRow
        For c = leftCol To rightCol

            ‘선택한 셀의 값을 “1”로 변경
            Cells(r, c).Value = “1”
        Next c
    Next r

End Sub

자칫 복잡하게 보일 수 있는 내용을 따로 함수로 만들었으므로(getLeft, getRight, makeRangeText) 이해하기 어렵지 않을 것이다.

현재 상기 코드는 Ctrl + e 키를 누를 경우 선택영역(커서가 위치한 1개의 셀 혹은 드래그한 여러개의 셀)의 값이 “1”로 변경되는 내용이다.

<여러 개의 셀을 선택한 상태에서 Ctrl + e 키를 누르면 값이 일괄 바뀐다>

3. 메인코드 개선 (선택영역의 값을 -1 처리)

메인코드를 약간 개선하면, 선택영역의 값 뒤에 특정한 문자열값을 붙이는 것도 가능하고, if문을 사용하면 일종의 조견표 처리도 가능하다. 예를 들면 “사자”, “호랑이”, “곰”은 “동물”로 바꾸고, “잡초”, “선인장”, “은행나무”는 “식물”로 바꾼다던지 말이다.

여기서는 선택영역의 값을 -1 처리하는 코드로 만들어보자.

마지막 부분을 아래와 같이 고치면 된다.

Sub 매크로1()

(중략)


‘선택영역의 좌측 상단셀부터 우측 하단셀까지, 반복문을 돌며 각 셀을 처리한다.
    For r = leftRow To rightRow
        For c = leftCol To rightCol
       
            Dim oneVal
            oneVal = Cells(r, c).Value
           

            ‘숫자일 경우만 동작
            If checkIsNumber(oneVal) Then
                ‘현재값에서 -1 처리
                Cells(r, c).Value = oneVal – 1
            End If
        Next c
    Next r

End Sub

보다시피 셀값이 숫자인 경우에만 -1 처리하는 코드이다.

이 때 셀값이 숫자인지 체크하는 함수인 checkIsNumber 함수가 필요한데, 단순무식하게 만들어보았다.

‘checkIsNumber : 문자열이 숫자인지 체크해서, 숫자일 경우 1을 리턴한다.
‘0 또는 자연수만 체크가능하다. 마이너스(음수) 또는 소수점이 있는 숫자는 해당없음.
Function checkIsNumber(str)

    Dim strLen
    strLen = Len(str)
   
    If strLen = 0 Then
        checkIsNumber = 0
        Exit Function
    End If
   
    Dim oneChar
    For i = 1 To strLen
        oneChar = Mid(str, i, 1)
       
        If oneChar <> “0” And oneChar <> “1” And oneChar <> “2” And oneChar <> “3” And oneChar <> “4” And oneChar <> “5” And oneChar <> “6” And oneChar <> “7” And oneChar <> “8” And oneChar <> “9” Then
            checkIsNumber = 0
            Exit Function
        End If
    Next i
   
    checkIsNumber = 1
End Function

정상적으로 작성되었다면, 마우스로 여러셀을 드래그해서 선택한 후, Ctrl + e 키를 누르면 0 이상의 숫자값에 한해서 -1 처리될 것이다. 전체 코드는 첨부파일로 넣어두겠다.

해당 코드를 사용하려면 VBA 윈도우 띄우기(엑셀에서 Atl + F11) -> 상단 메뉴의 [파일] – [파일 가져오기] – [180621.bas] 선택하고 엑셀에서 Ctrl + e 키를 눌러보면 된다.

이어지는 글 <엑셀VBA 입문 14강> On Error 구문의 사용 : https://blog.naver.com/bb_/221329746966
이어지는 글 <엑셀VBA 입문 15강> 텍스트 파일쓰기, 파일읽기 : https://blog.naver.com/bb_/221329757129
이어지는 글 <엑셀VBA 입문 16강> VBA로 워크시트 함수 활용하기 : https://blog.naver.com/bb_/221350410698

리눅스 find 명령어 (리눅스 파일 찾기, 리눅스 파일 검색)

리눅스 find 명령어 (리눅스 파일 찾기, 리눅스 파일 검색)

디스크 전체에서 파일 검색

find / -name “파일명”

ex) find / -name “*.class”

현재 디렉토리 하위 전체에서 파일 검색

find . -name “파일명”

ex) find . -name “*.class”

디스크 전체에서 폴더 검색

find / -name “폴더명” -type d

ex) find / -name “classes” -type d

현재 디렉토리 하위 전체에서 폴더 검색

find . -name “폴더명” -type d

ex) find . -name “classes” -type d

웹로직 파일 다운로드 테스트에 대한 기록

웹로직 파일 다운로드 테스트에 대한 기록

엊그제 웹로직 엔지니어가 와서 몇십분 아규한 일이 있었다. 훗날 참고하기 위해 새로 알게된 내용을 정리해본다.

먼저 타 사이트로 부터 전달받은 내용이다. 전달받은 내용이니 다소 사실과 다를 수도 있다. 얼마전 모 고객사(L사)가 오픈을 했는데 파일 다운로드가 몰려서 극도로 느려지는 성능 이슈가 발생했다. 다운로드 테스트 페이지를 만들어 확인했더니 동시에 여러대 PC에서 다운로드 시도하면 웹로직에 행이 걸리는 현상(제니퍼 불기둥) 발견. 이를 먹서를 바꿔 해결했다고 한다. 웹로직 12c의 기본 먹서는 multi io [멀티 아이오] 먹서인데, 이를 native 먹서인 DevPollSocket [디이브이 폴 소켓] 으로 바꿨다고 한다. (이때 오류가 발생하였는데 웹로직 쪽 버그였고 so파일을 패치해서 먹서가 적용되도록 조치했다고 한다)

타 고객사에서 문제가 발생했으니 우리쪽도 동일한 제품의 오픈을 앞둔 입장이라 확인이 필요했다. 다운로드 테스트 페이지를 전달받아 돌려보니 똑같은 현상이 발생, 웹로직 엔지니어를 불렀다. 아규해보니 테스트 과정 자체의 문제도 있었고, 발생하는 현상도 달랐다.

1. 익스플로러의 최대 다운로드 개수는 5개

이번에 작성한 다운로드 테스트 페이지의 내용은 파일 2000개를 0.5초 간격으로 다운받는 것이다. 간단히 설명하면 윈도우 onload시 iframe을 2000개 만들고, 셋타임아웃 500 간격으로 1메가~4메가 크기의 파일을 2000개 다운로드 받는다.

그런데 ie11의 경우 최대 다운로드 개수가 5개라고 한다. 새 창으로 브라우저를 여러 개 띄워도 똑같다. 이를 변경하기 위해서는 레지스트리를 수정하면 되는데, 구글에 “ie 창 개수 변경” 등으로 검색하면 바로 나온다고 한다.

특별한 조치없이 한 PC에서 파일 다운로드를 여러개 걸면, 5개까지는 진행이 되지만 6개부터는 소켓만 잡아놓고 연결은 하지 않는다고 한다. 이렇게 되면 웹로직에 행이 걸리며, 이때 행이 걸리는 현상은 정상적이고, 웹로직 측에서도 별달리 할 수 있는 조치가 없다고 했다.

다시 말해 PC 1대에서 2000개를 다운로드 받는 테스트 페이지로는, PC 2000대에서 각각 파일 1개씩 다운로드 받았을 때의 현상을 재현할 수 없다. 전자는 당연히 행이 걸리게 된다.

2. 클라이언트 대역폭을 알고 테스트 해야함

레지스트리를 변경해서 익스플로러가 파일 2000개를 동시에 다운로드 받을 수 있다고 쳐도 테스트에는 한계가 있다. 클라이언트 대역폭의 한계 때문이다.

클라이언트 대역폭이 1메가라고 하면, 파일 다운로드 속도는 1메가가 나올 것이다. 그런데 2000개 파일을 동시에 다운받는다면 각각의 속도는 1메가 나누기 2000 의 속도가 된다.

확인결과 테스트 페이지를 돌린 PC의 대역폭은 2메가 정도였다고 한다. 대역폭은 어떻게 알아내는거냐고, ipconfig를 보면 되는거냐고 물어보니, 웹로직 엔지니어 왈, 그냥 용량 큰 파일 1개를 다운로드 받을 때 브라우저에서 표시해주는 다운로드 속도를 보면 된다고 했다.

기존에 우리는 고객사 본사가 아닌 그 옆의 사무실에서 테스트를 진행하고 있었는데, 이후 본사 사무실에서 직접 테스트를 돌려보니 확실히 개선된 현상을 확인했다. 실제 고객 PC에서는 클라이언트 대역폭이 커서 다운로드가 빨랐던 것.

3. 먹서와 파일 다운로드에 따른 행과는 관련이 없음

이건 웹로직 엔지니어의 주장인데, 먹서와 파일 다운로드, 나아가 행 걸리는 현상은 전혀 연관이 없다고 했다. 하지만 바로 얼마전 타 고객사에서 먹서를 바꿔서 현상을 해결다고 전달받은 입장이 있었기 때문에, 이론적인 배경을 떠나 주장에 동의하기 힘들었다.

그래도 웹로직 엔지니어의 말이 옳다고 가정하고 정리해보면, 먹서라는 것은 출입구다. 사용자가 접속했을 때 먹서라는 놈을 거치게 되는데, 먹서는 그냥 사용자를 바이패스 해주는 입구 역할이고 다운로드와는 상관이 없다고 했다.

그럼 질문을 바꿔서, 어떤 문제가 있어서 먹서를 교체해야 한다고 가정하면, 그 어떤 문제는 무슨 문제일까요 하고 뒤집어 물어보았다. 그에 따르면 먹서는 크게 2 종류가 있는데, 자바 먹서와 네이티브 먹서가 있다고 했다. 네이티브 먹서는 OS 자체에 있는 먹서를 활용하는 것인데, 이게 잘 동작하지 않을 경우 자바 먹서를 사용한다고 했다. 자바 먹서는 먹서를 자바로 구현한 것이니 OS 단에서 지원하는 네이티브 먹서보다 당연히 느리다고 했다. 다시 말해 먹서는 디폴트 값이 잘 동작할 경우 변경하는 경우가 없으며, 디폴트 먹서가 잘 동작하지 않을 때에만 변경한다는 이야기였다.

우리는 타 고객사의 문제를 전달받았는지라 현재 먹서를 그곳과 같이 네이티브 먹서인 DevPollSocket 먹서로 변경해달라고 했는데, 현재 이 사이트는 네이티브 먹서의 일종인 nio [엔아이오] 먹서가 적용된 상태이고, 네이티브 먹서가 잘 적용되어 있는한 변경할 필요가 없다고 주장했다. 네이티브 먹서가 잘 안돌아서 자바 먹서로 바꾸는 경우는 있어도, 네이티브 먹서에서 네이티브 먹서로 바꾸는 경우는 없다고 했다.

그래서 네이티브 먹서에서 다른 네이티브 먹서로 바꾸면 어떤 문제가 있냐고 물어보았더니, 아무 문제가 없지만 아무런 효과도 없을 것이라 답하였다. 바꿀 이유가 없는 것이지 바꿔도 무방하다는 대답을 들었다. 우리는 일단 타 사이트에서 DevPollSocket 먹서로 잘 돌았으니, 리스크를 낮추기 위해 DevPollSocket 먹서로 적용해두는 것으로 결론지었다.

 

<엑셀VBA 입문 12강> 특정파일 특정시트의 특정셀을 가져오는 매크로

<엑셀VBA 입문 12강> 특정파일 특정시트의 특정셀을 가져오는 매크로

본 블로그에서 어떤 분의 질문을 받았다.

특정파일 특정시트의 특정셀을 가져오는 매크로는 어떻게 짜야 하는지 알려주실수 있을까요. ㅠ 응용해서 만들어 보려고 하는데 잘 안되네요. 파일은 매크로 설정 파일과 같은 디렉토리에 있습니다. 파일명과 시트명만 인자로 더 넘기면 될 것 같은데. 안 구해지네요. ㅠ

의미있는 질문으로 생각되어 강의로 만들어보았다.

1. 현재 셀의 값 구하기

엑셀에서는 현재 선택한 셀을 ActiveCell [액티브 셀]이라고 부른다. 현재 선택한 셀의 값은 ActiveCell.Value 이라고 쓰면 쉽게 얻는다.

2. 현재 시트에서 특정 셀의 값 구하기

현재 선택한 시트는 ActiveSheet [액티브 시트]라고 한다. 현재 선택한 시트에서 특정 셀의 값을 구하기 위해서는, Range 함수나 Cells 함수를 쓰면 된다.

현재 시트에서 A1 셀의 값 가져오는 방법이다. 둘 중 아무거나 쓰면 된다.

(1) ActiveSheet.Range(“A1”).Value

(2) ActiveSheet.Cells(1, 1).Value

(1)은 특정 셀의 이름으로 값을 가져오는 방법이고, (2)는 행, 열로 가져오는 방법이다.

참고로 현재 열려있는 시트의 이름을 가져오려면 ActiveSheet.Name 이라고 쓰면 된다.

3. 특정 시트에서 특정 셀의 값 구하기

엑셀에서는 여러 개의 시트(엑셀파일)를 묶어서 워크북이라고 한다. 현재 열려있는 파일은 ActiveWorkbook [액티브 워크북]이라고 한다. 다른 시트에서 특정 셀의 값을 구하려면, 워크북 내에서 특정 시트를 고르고, 그 안에서 특정 셀의 값을 가져오면 된다.

(현재 열고있는 엑셀 파일 상에서) 특정 시트를 가져오는 방법이다.

(1) ActiveWorkbook.Sheets(3)

(2) ActiveWorkbook.Sheets(“Sheet3”)

(1)은 시트 순서값으로 가져오는 방법이고, (2)는 시트 이름으로 가져오는 방법이다. Sheets(1)은 첫번째 시트를 뜻한다. 시트 순서값은 1부터 시작하므로 0 을 넣으면 오류가 발생한다.

참고로 화면을 특정 시트로 전환하려면 ActiveWorkbook.Sheets(“Sheet3”).Activate 이런 식으로 쓰면 된다.

4. 다른 파일의 특정 시트에서 특정 셀의 값 구하기

질문받은 내용이다. 특정파일 특정시트의 특정셀을 가져오는 방법이다.

GetObject 라는 함수를 이용해 엑셀 파일을 열면, 정말 쉽고 편안하게 조작할 수 있다.

엑셀 파일은 아래와 같이 읽는다.

Dim excelFile As Workbook
Set excelFile = GetObject(“C:\test\1.xlsx”)

절대경로로 되어있는데 상대경로로 하고 싶다면 ActiveWorkbook.Path 을 활용하면 된다. (현재 열고 있는 엑셀파일의 경로다. 값이 없다면 아직 엑셀파일이 저장되지 않은 상태이다)

GetObject 함수 인자로 특정 엑셀파일을 넘기면, 파일이 Workbook [워크북] 객체가 된다.

워크북 객체가 된 이상 시트를 얻고, 특정한 셀 값을 얻어내는건 무지 쉽다. 항목 “3. 특정 시트에서 특정 셀의 값 구하기”에 잘 나와있다.

4-1. 엑셀 파일 만들고 저장하기


아래와 같이 엑셀 파일을 작성하고, C 드라이브의 test 폴더를 만들어 1.xlsx 라는 파일명으로 저장한다.

 

4-2, 매크로 작성

새 파일을 만들고, 아래와 같이 매크로를 작성한다.

Sub 매크로1()

‘ 매크로1 매크로

‘ 바로 가기 키: Ctrl+k

Dim excelFile As Workbook
Set excelFile = GetObject(“C:\test\1.xlsx”)

Dim val

‘A1 값을 가져온다.
val = excelFile.Sheets(1).Range(“A1”).Value

MsgBox (“결과값 : ” & val)

‘다 사용한 파일 객체는 꼭 닫아준다.
excelFile.Close

End Sub

화면과 같이 특정 파일, 특정 시트의 특정 셀 값을 얻어오는 것을 확인할 수 있다.

이어지는 글 <엑셀VBA 입문 13강> 선택영역 한꺼번에 변경하기(VBA Selection)  : https://blog.naver.com/bb_/221303389424

이어지는 글 <엑셀VBA 입문 14강> On Error 구문의 사용 : https://blog.naver.com/bb_/221329746966
이어지는 글 <엑셀VBA 입문 15강> 텍스트 파일쓰기, 파일읽기 : https://blog.naver.com/bb_/221329757129

Github 사용법 (이클립스에서 Github에 커밋하기)

Github 사용법 (이클립스에서 Github에 커밋하기)

Git[깃]은 버전관리 시스템/형상관리 시스템이다. 쉽게 말해서 소스파일의 히스토리를 차곡차곡 저장해주는 시스템이다. 알다시피 소스파일이란 그냥 텍스트 파일이다. 그래서 말인데 개인적으로 깃헙을 소설가나 기자 등 문과출신도 많이 쓰면 좋겠다고 생각한다.

GitHub[깃헙]은 인터넷에 공개된 원격저장소다. Git만 쓰면 하드디스크에 저장되는데, 거기에 더해 Github까지 쓰면 인터넷상에 저장된다고 생각하면 된다.

한달에 7달러인가 내면 개인용(private)으로 쓸 수 있고, 그렇지 않으면 누구나 볼 수 있는 공개용(public)으로 쓸 수 있다.

2015년에 가입했었는데 한 번도 커밋하지 않았다. 내 소스를 남에게 공개하기 싫었다. 첫째로 남이 내 소스 가져가는게 싫었고, 둘째로 공개하기 창피하다고 생각했으니까.

생각이 바뀌어서 Github을 열심히 써보려고 한다. 훔쳐가봤자 얼마나 큰 손해겠으며, 쪽팔리면 얼마나 쪽팔릴 것인가. 생각해보면 나도 구글링으로 먹고 사는 마당인데 말이다. 게다가 훔쳐다가 잘쓰는 것도 정성이고 능력이다.

시작한다.

1. Github[깃헙]에 가입후 Repository[리포지토리] 생성

https://github.com/ 에 접속.

Sign up 이라는 단어를 찾아서 가입하자. 이메일 주소로 가입하면 된다.

그러고 나서 New repository 라는 버튼을 찾아서 Repository[리포지토리]를 만들자. 리포지토리는 저장소라는 뜻이다.

 

임시로 java 라는 리포지토리를 만들었다.

2. 이클립스에서 프로젝트 생성

이클립스를 켜서 적당한 프로젝트를 만든다. 개인적으로 System.out.println(“Hello Wolrd”)만 들어있는 프로젝트를 만들었다. 이 정도는 알아서 하시길.

3. 이클립스에서 Github 연결

이클립스 우측 상단 퍼스펙티브 영역의 Open Perspective 버튼을 누른다. 퍼스펙티브 영역이 어딘지 모르겠다고? 아래 그림을 참고하자.

Open Perspective 윈도우에서 Git을 선택하자.

만약 Git이 존재하지 않는다면 이클립스 버전이 낮은 경우다. 이클립스 상단메뉴의 Help – Eclipse Marketplace… 를 클릭해서 Git을 검색하고 다운받자. 이후 이클립스를 재기동하면 Git이 나올 것이다.

 

우측 상단 퍼스펙티브 영역에 Git 아이콘이 생겼을테고, 해당 아이콘을 클릭하자. 그러면 좌측에 아래 그림처럼 메뉴가 나온다. Clone a Git repository 를 클릭하자.

아래와 같이 Source Git Repository 가 뜬다. 여기에 이번에 만든 깃헙 리포지토리 주소를 붙여넣는다. 하단 Authentication 에는 깃헙 아이디와 패스워드를 입력한다.

참고로 깃헙 리포지토리 주소는 아래와 같은 화면에서 발췌할 수 있다.

 

<Next> 버튼을 클릭한다.

 

 

Destination 이라고 해서 로컬저장소를 지정할 수 있다. 기본값 그대로 두거나, 원하는 경로를 입력하고 Finish를 클릭한다.

 

Java 퍼스펙티브로 돌아와서, 프로젝트 위에서 마우스 우클릭하여 Team – Share Project… 를 클릭한다.


Repository 콤보박스 상에서 아까 만든 Repository를 선택하고, <Finish> 버튼을 클릭한다.

4. 이클립스에서 Github 커밋

프로젝트 위에서 마우스 우클릭하여 Team – Commit 을 클릭한다.

 

 

이클립스 하단부에 Git Staging[깃 스테이징]이라는 탭이 생겼을 것이다.

깃 스테이징의 좌상단인 Unstaged Changes 에서 커밋하고자 원하는 파일들을 선택하고 Add selected files to the index 명령을 적용한다. 아래 그림처럼 아이콘을 클릭해도 되고, 마우스 우클릭하여 단축 메뉴를 사용해도 된다.

 

깃 스테이징 우측의 Commit Message 란에 적당한 멘트를 써넣는다.

우측 하단의 Commit and Push 혹은 Commit 을 클릭하여 반영한다.

Commit 은 하드디스크(로컬저장소) 상에만 저장되는 것이고,

Commit and Push는 하드디스크(로컬저장소)에도 저장되지만 Github(인터넷 상의 원격저장소)에도 저장된다.

사용법으로는 Commit을 통해 하드디스크에 히스토리를 쌓다가, 어느정도 확정되었다 싶을 때 Commit and Push 로 여태까지의 내역을 원격저장소에 저장하는 방식이 일반적이다.

Commit and Push 가 끝나면 Github/인터넷에 잘 저장된 것이다. 계속해서 개발하고, 결과를 커밋하는 식으로 진행하면 된다.

[Spring4] 웹 프로젝트 생성

[Spring4] 웹 프로젝트 생성

(참고서적 : 스프링4 프로그래밍 입문 / 최범균 / 가메출판사 / 챕터9 : p234 ~ p249)

최범균의 스프링4 프로그래밍 입문은 챕터9부터(234페이지) 웹 프로젝트 생성을 다룬다.

본 블로그에서는 중간 챕터들을 건너뛰고, 곧바로 웹 프로젝트 생성을 다룬다.

단, 챕터1에 해당하는 개발환경 세팅은 반드시 해야 한다.

cf) [Spring4] 스프링 개발환경 세팅 (https://blog.naver.com/bb_/221268887576)

1. 메이븐 프로젝트 생성


1-1. 폴더 구성

C:\spring4\sp4-chap09 폴더 생성

이어서 C:\spring4\sp4-chap09\src\main\java 폴더 생성
이어서 C:\spring4\sp4-chap09\src\main\resources 폴더 생성

1-2. pom.xml 작성

C:\spring4\sp4-chap09\pom.xml 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″?>
<project xmlns=”http://maven.apache.org/POM/4.0.0
 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
 xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0
  http://maven.apache.org/xsd/maven-4.0.0.xsd“>
 <modelVersion>4.0.0</modelVersion>
 <groupId>sp4</groupId>
 <artifactId>sp4-chap09</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>

 <dependencies>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.2</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.0.1</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>4.1.0.RELEASE</version>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
     <source>1.7</source>
     <target>1.7</target>
     <encoding>utf-8</encoding>
    </configuration>
   </plugin>
  </plugins>
 </build>

</project>

1-3. 메이븐 컴파일

cmd 실행
cd C:\spring4\sp4-chap09
mvn compile

2. 이클립스에서 메이븐 프로젝트 임포트

이클립스 기동 – [File] – [Import…] – [Maven] 폴더 – Existing Maven Projects – [Next] 버튼 – Root Directory 에 C:\spring4\sp4-chap02 입력 하여 프로젝트 임포트한다.

3. 이클립스 톰캣 설정

3-1. 톰캣7 설치

톰캣7이 이미 설치되어 있는 경우 생략 가능하다.

톰캣7 웹페이지 : http://tomcat.apache.org/download-70.cgi
톰캣7 다운로드 바로가기 : http://mirror.apache-kr.org/tomcat/tomcat-7/v7.0.86/bin/apache-tomcat-7.0.86.zip

톰캣은 다운로드 받아서 특정 위치에 압축을 풀면 끝이다.

예) C:\devtool\apache-tomcat-7.0.86

3-2. 이클립스 서버 세팅 (톰캣7)

상단 메뉴의 [Window] – [Preferences] – 좌측 리스트의 [Server] – [Runtime Environments] – [Add] 버튼 클릭 – [Apache Tomcat v7.0] 선택 – [Next] – Tomcat installation directory 항목에 톰캣 경로 입력(ex: C:\devtool\apache-tomcat-7.0.86) – [Finish] – [Apply and Close] 버튼 클릭



4. 각종 설정파일(xml) 작성


4-1. spring-mvc.xml

/sp4-chap09/src/main/resources/spring-mvc.xml 파일을 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans
 xmlns:mvc=”http://www.springframework.org/schema/mvc
 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
 xsi:schemaLocation=”http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/mvc
  http://www.springframework.org/schema/mvc/spring-mvc.xsd“>

 <mvc:annotation-driven />

 <mvc:default-servlet-handler />

 <mvc:view-resolvers>
  <mvc:jsp prefix=”/WEB-INF/view/” />
 </mvc:view-resolvers>

</beans>

4-2. web.xml

/sp4-chap09/src/main/webapp/WEB-INF/web.xml 파일을 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
 xmlns=”http://java.sun.com/xml/ns/javaee
 xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
 version=”3.0″>

 <servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>
   org.springframework.web.servlet.DispatcherServlet
  </servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>
    classpath:spring-mvc.xml
    classpath:spring-controller.xml
   </param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

 <filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>
   org.springframework.web.filter.CharacterEncodingFilter
  </filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>UTF-8</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

</web-app>

4-3. spring-controller.xml

/sp4-chap09/src/main/resources/spring-controller.xml 파일을 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans
 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
 xsi:schemaLocation=”http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd“>

 <bean class=”chap09.HelloController” />

</beans>

5. 소스코드 작성

5-1. HelloController.java

/sp4-chap09/src/main/java/chap09/HelloController.java 파일을 작성한다.

package chap09;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloController {
 
 @RequestMapping(“/hello”)
 public String hello(Model model, @RequestParam(value = “name”, required = false) String name) {
  model.addAttribute(“greeting”, “안녕하세요, ” + name);
  return “hello”;
 }
}

5-2. hello.jsp

/sp4-chap09/src/main/webapp/WEB-INF/view/hello.jsp 파일을 작성한다.

<%@ page contentType=”text/html; charset=utf-8″ %>
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
인사말: ${greeting}
</body>
</html>

6. 이클립스에서 톰캣7 기동

프로젝트 폴더(sp4-chap09)에서 마우스 우클릭 – [Run As] – [Run On Server] 하면 서버 기동된다.

404 페이지가 뜨면 기동된 것이다.

이제 http://localhost:8080/sp4-chap09/hello?name=guest 로 접속한다.

아래처럼 나오면 성공이다.

[Spring4] 메이븐 프로젝트 생성과 임포트

[Spring4] 메이븐 프로젝트 생성과 임포트

스프링 개발 실습을 위하여 기본적인 형태의 메이븐 프로젝트를 생성해본다. 메이븐은 프로젝트의 라이브러리를 관리해주는 솔루션이다.

(참고서적 : 스프링4 프로그래밍 입문 / 최범균 / 가메출판사 / 챕터2 : p32 ~ p50)

1. 메이븐 프로젝트 생성

1-1. 폴더 구성

C:\spring4\sp4-chap02 폴더를 생성한다. 이어서 아래와 같은 구조가 되도록 폴더 생성한다.


C:

└ spring4
    └ sp4-chap02
        └ src
            └main
                └java
                └resources


1-2. pom.xml 생성

C:\spring4\sp4-chap02 폴더 내에 pom.xml 파일을 생성한다. 내용은 아래처럼 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<project xmlns=”http://maven.apache.org/POM/4.0.0
 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
 xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0
  http://maven.apache.org/xsd/maven-4.0.0.xsd“>
 <modelVersion>4.0.0</modelVersion>
 <groupId>sp4</groupId>
 <artifactId>sp4-chap02</artifactId>
 <version>0.0.1-SNAPSHOT</version>

 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>4.1.0.RELEASE</version>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
     <source>1.7</source>
     <target>1.7</target>
     <encoding>utf-8</encoding>
    </configuration>
   </plugin>
  </plugins>
 </build>

</project>

1-3. 메이븐 컴파일

cmd 로 들어가서
cd C:\spring4\sp4-chap02
mvn compile

이라고 입력한다. 아래와 같이 진행되면 정상이다.



※ 여기서 잠시, 메이븐을 쓰는 이유 간략정리.

메이븐은 중앙 리포지토리(repo.maven.apache.org)의 필요한 파일(아티팩트)을 로컬 리포지토리(C:\Users\[사용자명]\.m2\repository)에 복사(다운로드)한다.

아티팩트란 메이븐이 사용하는 단위로써, 모듈 1개를 의미한다. jar 파일명의 경우 “아티팩트이름-버전.jar” 라고 생각하면 된다.

메이븐은 한 번 로컬 리포지토리에 다운받으면 그 다음부터는 원격 리포지토리에서 다운받지 않는다. (다시 mvn compile을 실행하면 이미 받았던 아티팩트는 건너뛴다.)

특히, 다운받으려는 아티팩트가 의존하는 다른 아티팩트들도 함께 다운로드 해준다. 이게 메이븐의 특장점.


2. 메이븐 프로젝트 임포트

이클립스 기동 – [File] – [Import…] – [Maven] 폴더 – Existing Maven Projects – [Next] 버튼 – Root Directory 에 C:\Spring\sp4-chap02 입력 하면 프로젝트 임포트 된다.

3. 예제코드 작성


3-1. Greeter.java
이클립스 탐색기상의 /src/main/java 밑에 chap02 패키지 생성하고, 그 아래 Greeter.java 파일 생성한다.

내용은 다음과 같이 작성한다.

package chap02;

public class Greeter {
 
    private String format;
 
    public String greet(String guest) {
        return String.format(format, guest);
    }
 
    public void setFormat(String format) {
        this.format = format;
    }
}

3-2. applicationContext.xml
이클립스 탐색기상의 /src/main/resources 밑에 applicationContext.xml 파일 생성한다.
내용은 다음과 같이 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
    xsi:schemaLocation=”http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd“>

    <bean id=”greeter” class=”chap02.Greeter”>
        <property name=”format” value=”%s, 안녕하세요!” />
    </bean>

</beans>

3-3. Main.java
이클립스 탐색기상의 /src/main/java/chap02 패키지 밑에 Main.java 파일 생성한다. (생성시 public static void main(String[] args) 체크하여 만든다.)

내용은 다음과 같이 작성한다.

package chap02;

import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(“classpath:applicationContext.xml”);
        Greeter g = ctx.getBean(“greeter”, Greeter.class);
        String msg = g.greet(“스프링”);
        System.out.println(msg);
        ctx.close();
    }

}

실행하면(Main.java 파일 우클릭 – Run As – Java Application 클릭) 아래와 같이 동작한다.

현재 new를 쓰지 않고 GenericXmlApplicationContext 클래스를 사용해 객체를 생성 및 초기화하고 있다. 책에 따르면, 스프링의 핵심 기능이 바로 객체의 생성 및 초기화라고 한다.

객체 정보를 가져오는 방법은 3가지가 있는데, (1) xml, (2) 자바 설정코드, (3) 그루비 설정코드 이다. xml을 사용시 GenericXmlApplicationContext 클래스를, 자바 어노테이션 사용시 AnnotationConfigApplicationContext 클래스를, 그루비 사용시 GenericGroovyApplicationContext 클래스를 사용하면 된다.

참고로 이렇게 만들어지는 객체들은 기본적으로 싱글톤이다. 실제로 getBean을 2번해도 3번해도 동일한 객체가 튀어나오게 된다. (등호 2개로 == 이렇게 비교해도 true가 나온다. 싱글톤이니 같은 주소값을 갖기 때문.) 싱글톤을 원하지 않는다면 프로토타입 범위로 설정하면 된다.

[Spring4] 스프링 개발환경 세팅

[Spring4] 스프링 개발환경 세팅

스프링 개발 실습을 위하여 스프링 개발환경을 세팅해본다. JDK 7 설치, 메이븐 설치, 환경변수 설정, 이클립스 설치를 하면 된다.

(참고서적 : 스프링4 프로그래밍 입문 / 최범균 / 가메출판사 / 챕터1 : p20 ~ p29)

1. JAVA JDK 7 설치 (Java SE Development Kit 7u80)

웹페이지 : http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html

다운로드 바로가기 (Windows x64) : http://download.oracle.com/otn/java/jdk/7u80-b15/jdk-7u80-windows-x64.exe

다운로드 바로가기 (Windows x86) : http://download.oracle.com/otn/java/jdk/7u80-b15/jdk-7u80-windows-i586.exe


2. 메이븐 설치

http://maven.apache.org/ 접속해서 Download 클릭 -> Downloading Apache Maven 3.5. 다운로드

다운로드 바로가기 : http://mirror.navercorp.com/apache/maven/maven-3/3.5.3/binaries/apache-maven-3.5.3-bin.zip

C:\devtool 아래에 압축 풀면 된다.
(C:\devtool\apache-maven-3.5.3\bin\mvn.cmd 위치하면 성공)

3. 환경변수 설정

내 PC 마우스 우클릭 – [속성] – 좌측의 [고급 시스템 설정] – [고급] 탭 – [환경변수] 버튼 – 사용자 변수 리스트 하단의 [새로 만들기] 버튼 클릭

환경변수 2개 추가(자바, 메이븐), 1개 편집(Path) 요망

3-1. 변수이름 : JAVA_HOME / 변수값 : C:\java\jdk1.7.0_80
3-2. 변수이름 : M2_HOME / 변수값 : C:\devtool\apache-maven-3.5.3
3-3. 변수이름 : Path / 변수값 : %M2_HOME%\bin ([편집] 버튼으로 기존 문자열 뒤에 추가)

※ 아래 그림처럼 cmd 에서 mvn -vesion 쓰고 엔터쳤을 때 에러나지 않고 Maven home 등등이 출력되면 성공이다.

4. 이클립스 설치


http://www.eclipse.org/downloads/ 접속해서 Eclipse IDE for Java EE Developers 다운로드

웹페이지 : http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/oxygen3a

다운로드 바로가기  (Windows 64-bit) :

http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/oxygen/3a/eclipse-jee-oxygen-3a-win32-x86_64.zip

다운로드 바로가기  (Windows 32-bit) :

http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/oxygen/3a/eclipse-jee-oxygen-3a-win32.zip

적당한 위치에 압축 풀어놓으면 된다. ex) C:\spring\eclipse

※ 이클립스 인코딩 변경 : 상단 메뉴의 [Window] – [Preferences] 선택 – 좌측 리스트의 [General] – [Workspace] 선택 – 제일 하단의 Text file encoding 항목에서 Other에 체크, UTF-8 이라고 입력한다.

스프링 개발환경 세팅이 완료되었다.

<엑셀VBA 입문 11강> 배열 다루기

<엑셀VBA 입문 11강> 배열 다루기

본 게시글의 강의 내용이 너무 어렵게 쓰여진 관계로, 다시 쓴 강의의 링크를 첨부합니다.

아래 링크로 조회해주세요. 감사합니다.

<엑셀VBA 입문 11-2강> 배열(Array) : https://blog.naver.com/bb_/221313490342

VBA 학습 단상

VBA 학습 단상

VBA는 내가 어릴 때(중3때) 배워둔거다. 정말 기가 막히게 울궈먹었다. 자격증 딸 때 쓰고, 군대 행정병 때 쓰고, 대학 과제할 때 쓰고, 공모전 때 쓰고, 언론사 알바할 때 쓰고, 지금 회사에서 쿼리 만들 때도 쓴다. 그때마다 일거리는 왕창 줄어들곤 했다.

2013년에 내 블로그 보고 전화가 온적 있는데 울산 내려와서 VBA해주면 지금 내가 받는(2018년 현재) 월급보다 많이 준다고 했다. 돈 받으면 진짜 어려운거 시킬까봐 돈 안받고 온라인으로만 계속 도와줬는데, 서너달에 할거 이삼주만에 하고 계속 감사인사 하시더라.

내가 VBA 잘하는 것도 아니다. 정말 자바에 비하면 전혀 못하는 수준이다. if문 쓰고 for문 쓰고 루프문 돌리는 정도다. 객체지향언어인데 객체지향으로 써본 적도 한 번 없다. 정식으로 배운 기간은 한달도 안된다. 기본만 아는데도 엄청나게 유용하게 사용해왔다.

그래서 사람들한테 맨날 VBA 배우라고 노래부르고 다니는거다. VBA 진짜 잘하는 사람들은 VB닷넷 개발자라고 보면 된다. 내가 하루에 12시간씩 자바하듯이 VB하는 애들이다. 그렇게 잘할 필요 없고 잘할 수도 없다. 난 정말 못하는데도 큰 효과를 봤고, 그렇기 때문에 남에게 자신있게 추천하는거다.

<엑셀VBA 입문 10강> VBA로 웹파싱하기 (HTML소스 가져오기)

<엑셀VBA 입문 10강> VBA로 웹파싱하기 (HTML소스 가져오기)

오늘은 간단하게 VBA로 웹파싱하는 방법을 배워본다. 웹파싱이란 웹사이트의 HTML소스를 가져와서 분석하는 것을 말한다. 파싱(Parsing)은 구문 분석이라는 뜻을 갖고 있다.

파싱해볼 대상은 구글이다. 구글 주소는 http가 아닌 https로 시작한다. 검색결과를 얻고 싶으면 구글 주소 뒤에 “search?q=검색어”를 붙이면 된다.

예를 들어 구글에 VBA를 검색하고 싶다면, https://google.com/search?q=VBA 라는 주소로 접속하면 된다. 아래 화면과 같이 말이다.

 


[구글 주소 뒤에 “search?q=검색어”를 붙이면 곧바로 검색페이지에 도달할 수 있다]

화면에 표시한 부분인 “검색결과 약 00000 개” 라는 부분을 실시간으로 가져오고 싶다고 가정하자. 이렇게 웹사이트 소스의 일부를 가져오는 행위를 파싱이라고 한다.

일단 전체 소스가 어떻게 생겼는지 대강 살펴보자. 마우스 우클릭 – [소스 보기] 를 클릭하거나, 키보드 F12 키를 누르면 HTML 소스를 볼 수 있다.


[구글 페이지의 HTML 소스다. 구글이니까 이렇게 복잡하지 웹페이지에 따라 간단한 경우도 많다]

현재 보고 있는 이 소스가 구글의 HTML소스다. 구글이니까 엄청 복잡하지, 실전에서 분석하고자 하는 페이지는 간단할 수도 있다.

먼저 이 소스 전체를 가져오는 작업을 할 것이다. VBA에서는 아래와 같이 짧은 함수로 HTML 소스를 가져올 수 있다.

Function getHtml(url As String) As String
    Set httpObj = CreateObject(“MSXML2.XMLHTTP”)
    httpObj.Open “GET”, url, False
    httpObj.send
    getHtml = httpObj.responseText
End Function

실제로 이 함수를 만든 후 시트에서 =getHtml(“http://blog.naver.com/bb_“)라고 쓰면 본 블로그의 HTML 소스가 엑셀 시트 상에 삽입될 것이다.

[getHtml 함수는 단 4줄로 특정 웹페이지의 HTML 전체소스를 가져오는 강력한 함수다]

이렇게 전체 소스를 가져오는 것 자체는 그다지 의미가 없기 때문에Ctrl + k 단축키로 동작하는 매크로를 만들어보겠다. 매크로를 만드는 방법을 까먹었다고? 간단하게 설명하겠다.

* VBA (단축키로 실행되는) 매크로 함수 만드는 방법

엑셀 상단메뉴의 [보기] – [매크로] 단추 하단의 화살표 클릭하여 [매크로 기록] – Ctrl 다음 빈칸에 영문자 k 입력하고 [확인] – 곧바로, [매크로] 단추 하단의 화살표 클릭하여 [기록 중지] – Alt + F11 키 눌러서 VBA 윈도우 띄움 – VBA창 좌측 탐색기에서 Module1 더블클릭 – Sub 매크로1() 안에서 코딩 시작

매크로를 아래와 같이 작성한다.

Sub 매크로1()

‘ 매크로1 매크로

‘ 바로 가기 키: Ctrl+k

    Dim inputVal
    inputVal = InputBox(“검색할 단어를 입력해주세요.”)
   
    If Len(inputVal) < 1 Then
        MsgBox (“빈값입니다.”)
        Exit Sub
    End If
   
    ‘결과를 담을 변수
    Dim result
    result = “”
   
    ‘HTML 소스를 가져온다
    Dim html
    html = getHtml(“https://www.google.com/search?q=” & inputVal)
   
    Dim beginIdx
    Dim endIdx
    beginIdx = 0
    endIdx = 0
   
    ‘HTML에서 [검색결과]라는 단어를 찾는다.
    beginIdx = InStr(1, html, “검색결과”)
   
    ‘이어서 여는태그(<) 를 찾는다.
    If beginIdx > 0 Then
        endIdx = InStr(beginIdx + 1, html, “<“)
    Else
        MsgBox (“HTML에서 단어 [검색결과]를 찾을 수 없습니다.”)

        Exit Sub
    End If
   
    ‘여는태그(<)가 존재할 경우
    If endIdx > 0 Then
        result = Mid(html, beginIdx, endIdx – beginIdx)
    Else
        result = Mid(html, beginIdx)
    End If
   
    MsgBox (“[” & result & “]”)

End Sub

역시 문자열을 다루기 위해 InStr 함수와 Mid 함수를 활용하고 있다.

InStr 함수는 InStr(시작위치, 대상값, 검색값) 으로 사용한다.

Mid 함수는 Mid(자를텍스트, 시작위치, 최종길이)로 사용한다. (만약 마지막 3번째 인자값을  사용하지 않고 Mid(자를텍스트, 시작위치) 로 사용한다면, 시작위치부터 끝까지 자르게 된다.)

매크로의 내용을 간단히 요약하자면, 먼저 HTML 소스를 전부 가져온다. 그 후 “검색결과”라는 단어를 찾고, 이어서 HTML의 여는 태그를 뜻하는 “<” 기호를 찾는다. “검색결과” 단어부터 “<“기호 바로 앞까지가, 우리가 가져오고 싶은 부분이기 때문이다.

원하는 부분을 얻기 위해 HTML 소스코드의 어떤 부분을 잘라내야 하는지는, HTML 소스코드를 메모장에 갖다놓고 이리저리 살펴봐야 알 수 있다.

언제나 소스코드 전체를 이해하거나 파악할 수는 없다. 소스코드란 그저 텍스트일 뿐이니 자신감을 갖고, 원하는 부분을 찾아오는데 집중하면 된다. 

결과적으로 VBA 코드는 아래와 같이 동작할 것이다.

여기까지가 웹파싱의 기본이다.

실시간 웹파싱은 웹페이지의 내용(HTML 소스코드)가 변경될 경우 프로그램도 같이 수정해줘야 하는 단점이 있다.

하지만 만약 정기적으로 특정 웹페이지의 내용을 긁어다가 활용해야 하는 업무를 맡고 있다면, 웹파싱만큼 훌륭한 솔루션이 없다.

칼퇴를 기원한다.

이어지는 글 <엑셀VBA 입문 11-2강> 배열(Array) : https://blog.naver.com/bb_/221313490342

​이어지는 글 <엑셀VBA 입문 12강> 특정파일 특정시트의 특정셀을 가져오는 매크로 : https://blog.naver.com/bb_/221288948784
이어지는 글 <엑셀VBA 입문 13강> 선택영역 한꺼번에 변경하기(VBA Selection)  : https://blog.naver.com/bb_/221303389424

<엑셀VBA 입문 9강> 특정 단어의 개수를 세는 방법

<엑셀VBA 입문 9강> 특정 단어의 개수를 세는 방법

9강입니다. 연재가 늦어져서 죄송합니다.

오늘은 특정 단어를 세는 함수를 만들어볼까 합니다.

오늘 내용은 어렵지만 가치가 있는 내용입니다.

오히려, 다소 어렵다면 잘 따라오고 있다고 생각하면 됩니다. 차분히 읽으면 이해됩니다.

1. include 함수

먼저 특정 단어가 존재하는지 검사하는 함수를 만들어봅시다.

이름은 include[인크루드]라고 해보겠습니다. 우리말로 [포함하다]라는 뜻입니다. 참고로 함수는 동사로 써주는게 기본입니다.

아래와 같이 동작합니다.

 

아래와 같이 코딩해보았습니다.

Function include(cell, textToFind)

    ‘cell의 값을 가져옴
    Dim val
    val = Range(cell, cell).Value
   
    ‘cell의 값 1번째 글자부터 textToFind 값 찾기
    Dim idx
    idx = InStr(1, val, textToFind, vbTextCompare)

    ‘인덱스 값을 리턴
    If idx > 0 Then
        include = 1
    Else
        include = 0
    End If

End Function

8강까지의 내용을 잘 따라오셨다면 큰 어려움은 없습니다. 그래도 헷갈릴지 몰라 InStr 함수에 대해 간단히 소개합니다.

InStr 함수는 특정 텍스트(찾을값)이 대상 텍스트(대상값)의 몇 번째 글자수에 위치해있는지 알아보는 함수입니다.

InStr(시작인덱스, 대상값, 찾을값, vbTextCompare) 이렇게 사용합니다.

예를 들면 InStr(1, “이 문장에서 사과라는 단어를 찾습니다”, “사과”, vbTextCompare) 와 같이 사용합니다.

시작인덱스가 1이면 첫번째 글자부터 찾습니다.

그 결과 리턴값이 0 이면 대상값 중에 찾을값이 존재하지 않는 상태입니다.

리턴값이 0 보다 크면 존재하는 겁니다. 예를 들어 리턴값이 n이면 대상값의 n번째 자리수에 해당 텍스트가 존재하는 겁니다.

2. 개선된 include 함수 (includeMulti 함수)

이번엔 include 함수를 개선해보겠습니다. 개선된 include함수라고 해서, 이름은 includeMulti[인크루드 멀티]로 붙여보겠습니다.

아래와 같이 사용합니다.

 

보다시피 여러 범위에서 특정 단어가 존재하는지를 찾아내는 함수입니다.

이 함수를 만들기 위해서는 지난 시간(8강)에서 만든 getContent 함수가 필요합니다.

기억나실지 모르지만, getContent 함수는 내용이 제법 길고 까다로웠습니다.

이런 함수는 만들 때 한 번 이해해두고, 다음에는 그냥 잘 갖다 쓰면 됩니다.

그대로 가져와보겠습니다.

Function getContent(cell As Range)
    Dim resultVal
    resultVal = “”
   
    ‘addr 변수에 문자열을 저장한다. $가 포함되어 있다면 제거한다.
    ‘ex) cell.Address = “$A$1:$D$10” 이라면 addr = “A1:D10” 이 된다.
    ‘ex) cell.Address = “$A$1” 이라면 addr = “A1” 이 된다.
    Dim addr
    addr = cell.Address & “”
    addr = Replace(addr, “$”, “”)
   
    Dim colonIdx
    colonIdx = InStr(addr, “:”)
    If colonIdx > 0 Then
        ‘콜론이 존재하는 경우(다중범위)
        Dim leftAddr, leftColNum, leftRowNum
        leftAddr = Mid(addr, 1, colonIdx – 1)
        leftColNum = Range(leftAddr).Column
        leftRowNum = Range(leftAddr).Row
       
        Dim rightAddr, rightColNum, rightRowNum
        rightAddr = Mid(addr, colonIdx + 1, Len(addr) – colonIdx)
        rightColNum = Range(rightAddr).Column
        rightRowNum = Range(rightAddr).Row
       
        For r = leftRowNum To rightRowNum
            For c = leftColNum To rightColNum
                resultVal = resultVal & Cells(r, c).Value
                ‘MsgBox (“(” & r & “,” & c & “) : ” & Cells(r, c).Value)
            Next c
        Next r
       
        getContent = resultVal
    Else
        ‘콜론이 존재하지 않는 경우(단일범위)
        resultVal = Range(cell, cell).Value
        getContent = resultVal
    End If

End Function

한 번 잘 만들어둔 함수는 다음에 그냥 갖다 쓰면 됩니다.

내용을 다시 볼 필요가 없기도 합니다.

이렇게 안쪽 내용을 보지 않고 그냥 갖다쓸 수 있는 함수의 특성을 “블랙박스”(안쪽이 보이지 않는 검은색 상자)라고 합니다.

눈치채셨겠지만, 함수는 블랙박스에 가까울수록 좋아요.

안쪽 내용을 열심히 들여다보지 않아도, 쉽게 갖다쓸 수 있어야 좋다는 뜻입니다. 그래서 함수명을 잘 붙이는게 중요합니다.

여튼 includeMulti 함수는 아래와 같이 만듭니다.

Function includeMulti(cell As Range, textToFind)

    ‘대상값을 가져옴 (getContent 함수 사용)
    Dim val
    val = getContent(cell)
   
    ‘대상값 1번째 글자부터 textToFind 값 찾기
    Dim idx
    idx = InStr(1, val, textToFind, vbTextCompare)

    ‘인덱스 값을 리턴
    If idx > 0 Then
        includeMulti = 1
    Else
        includeMulti = 0
    End If

End Function

보시다시피 대상값 val을 가져올 때 Range(cell, cell).Value 이 아닌, 이미 만들어둔 getContent 함수를 사용했습니다. 이렇게 함수 안에서 다른 함수를 부르고, 작은 함수를 여러개 모아서 큰 함수를 만드는걸 잘해야 됩니다. 이게 코딩의 기본이고 VBA의 기본입니다.

아시다시피 getContnet 함수는 여러 셀 대상으로 가용하지만 1개 셀 대상으로도 가용합니다.

따라서 includeMulti 함수도 여러 셀 대상으로 가용하고 1개 셀 대상으로도 가용합니다.

3. getCount 함수

이어서 getCount 함수를 만들어봅니다. 양이 많지만 힘을 내서 만들어봅니다.

getCount 함수는 아래와 같이 사용합니다.

include 함수는 단순히 “사과”라는 단어가 존재하는지, 존재하지 않는지에 따라 1 과 0 으로 표시합니다.

이에 대비해 getCount 함수는 “사과”라는 단어를 세고 있습니다.

아래와 같이 코딩합니다.

Function getCount(cell, textToFind)

    ‘예외처리: 찾을값이 없으면 0 리턴
    If Len(textToFind) = 0 Then
        getCount = 0
        Exit Function
    End If

    ‘대상값을 가져옴
    Dim val
    val = Range(cell, cell).Value
   
    ‘예외처리: 대상값이 없으면 0 리턴
    If Len(val) = 0 Then
        getCount = 0
        Exit Function
    End If
   
    ‘textToFind 의 글자수
    Dim textLen
    textLen = Len(textToFind)
   
    ‘결과값 변수
    Dim resultCount
    resultCount = 0
   
    ‘현재 인덱스
    Dim curIdx
    curIdx = 0
   
    ‘기준 인덱스
    Dim axisIdx
    axisIdx = 1

    Do
        curIdx = InStr(axisIdx, val, textToFind, vbTextCompare)
        If curIdx > 0 Then
            resultCount = resultCount + 1
            axisIdx = curIdx + textLen
        Else
            Exit Do
        End If
    Loop

    getCount = resultCount

End Function

이번에 만든 getCount 함수 역시 InStr 함수를 기본으로 하고 있습니다.

Do Loop [두 루프] 문을 만들었으니, 무한루프에 걸리지 않게 조심해야 합니다. 참고로 무한루프에 걸렸다 싶으면 Ctrl + Break 키를 누르면 풀려납니다(함수 강제중지). Break 키는 키보드 최상단 우측부에 있습니다. 키를 찾기 힘드므로 (1) 저장을 자주 하시고 (2) 함수를 잘 짜서 무한루프 늪에 빠지지 않도록 합시다.

axisIdx는 axis index를 의미하는 변수입니다. 기준이 되는 인덱스라는 뜻이죠. curIdx 는 current index를 의미하는 변수입니다. 현재 인덱스를 담아두는 변수입니다. (참고로 axis[엑시스]는 “축”이라는 뜻입니다. 이를테면 “악의 축”은 the axis of evil [디 엑시스 오브 이블]이라고 합니다.)

처음에 axisIdx 의 초기값이 1입니다. 첫번째 글자로부터 찾을값(textToFind)을 검색합니다.

찾으면 curIdx의 값이 0 초과의 값을 갖게 되고, resultCount 값을 1 플러스 한다음 루프문 안에서 계속 검색합니다.

찾아내지 못하면 0 미만의 값을 가지므로 Exit Do 로 루프문을 나가게 됩니다.

여기서 약간 헷갈릴 수 있는 부분이 axisIdx = curIdx + textLen 라는 부분입니다.

axisIdx, 즉 기준이 되는 인덱스 구할 때, 찾은 인덱스(curIdx)에 찾을 글자수(textLen)를 더하고 있습니다.

사실 axisIdx = curIdx + 1 이렇게만 해도 됩니다.

만약 axisIdx = curIdx, 이렇게 할 경우 axisIdx 값은 변함이 없으므로 무한루프에 걸릴 가능성이 있습니다.

그런데 axisIdx = curIdx + 1 이렇게만 해두면 바로 다음 글자 인덱스부터 찾으므로 글자를 겹쳐 찾습니다.

무슨 말인가 하면,

“상상하다”이라는 문장이 있을 때, “상상”의 개수를 세어보면 1개입니다.

그럼, “상상상하다”라는 문장이 있을 때, “상상”의 개수를 세어보면  몇 개 일까요?

누군가에게는 1개이고, 누군가에게는 2개입니다.

겹치는 부분이 있기 때문입니다.

axisIdx = curIdx + 1 로 로직을 짜면 2개가 되고,

axisIdx = curIdx + textLen 로 로직을 짜면 1개가 됩니다.

저는 후자가 맞다고 보기 때문에(이미 검사한 부분은 지나가야 한다고 생각하기 때문에) textLen 을 더해주었습니다.

4. 개선된 getCount 함수 (getCountMulti 함수)


이어서 getCountMulti 함수를 만들어봅니다. 거의 다 왔습니다.

아래와 같이 사용합니다.

어떻게 만드는 걸까요?

include 함수를 개선한 방식과 똑같습니다.

val = Range(cell, cell).Value 부분을 val = getContent(cell) 로 교체해주고,

getCount 라는 단어를 getCountMulti 로 다 바꿔주면 끝입니다.

앞서와 마찬가지로, getCountMulti 함수는 셀 n개 대상으로도 사용 가능하지만, 셀 1개 대상으로도 사용 가능합니다. getContent 함수가 그랬기 때문이죠.

코드를 남겨둡니다.

Function getCountMulti(cell As Range, textToFind)

    ‘예외처리: 찾을값이 없으면 0 리턴
    If Len(textToFind) = 0 Then
        getCountMulti = 0
        Exit Function
    End If

    ‘대상값을 가져옴
    Dim val
    val = getContent(cell)
   
    ‘예외처리: 대상값이 없으면 0 리턴
    If Len(val) = 0 Then
        getCountMulti = 0
        Exit Function
    End If
   
    ‘textToFind 의 글자수
    Dim textLen
    textLen = Len(textToFind)
   
    ‘결과값 변수
    Dim resultCount
    resultCount = 0
   
    ‘현재 인덱스
    Dim curIdx
    curIdx = 0
   
    ‘기준 인덱스
    Dim axisIdx
    axisIdx = 1

    Do
        curIdx = InStr(axisIdx, val, textToFind, vbTextCompare)
        If curIdx > 0 Then
            resultCount = resultCount + 1
            axisIdx = curIdx + textLen
        Else
            Exit Do
        End If
    Loop

    getCountMulti = resultCount

End Function

2020.04.19(화) 내용추가

현재 getCountMulti 함수는 1개의 셀에 단어가 2번 포함되어 있을 경우 2개로 계산합니다.

ex) 1개의 셀 내의 값이 “사과사과”일 경우 사과를 2개로 계산

1개의 셀 내에 단어가 2번 들어가더라도 1개로 계산되게 하려면 아래 getCountMulti2 함수를 사용하기 바랍니다.

=getCountMulti2(A1:C3,”사과”) 이런식으로 사용 가능합니다.

Function getCountMulti2(cell As Range, textToFind)
    Dim resultCount
    resultCount = 0
   
    Dim idx
    idx = 0
   
    Dim resultVal
    resultVal = “”
   
    ‘addr 변수에 문자열을 저장한다. $가 포함되어 있다면 제거한다.
    ‘ex) cell.Address = “$A$1:$D$10” 이라면 addr = “A1:D10” 이 된다.
    ‘ex) cell.Address = “$A$1” 이라면 addr = “A1” 이 된다.
    Dim addr
    addr = cell.Address & “”
    addr = Replace(addr, “$”, “”)
   
    Dim colonIdx
    colonIdx = InStr(addr, “:”)
    If colonIdx > 0 Then
        ‘콜론이 존재하는 경우(다중범위)
        Dim leftAddr, leftColNum, leftRowNum
        leftAddr = Mid(addr, 1, colonIdx – 1)
        leftColNum = Range(leftAddr).Column
        leftRowNum = Range(leftAddr).Row
       
        Dim rightAddr, rightColNum, rightRowNum
        rightAddr = Mid(addr, colonIdx + 1, Len(addr) – colonIdx)
        rightColNum = Range(rightAddr).Column
        rightRowNum = Range(rightAddr).Row
       
        For r = leftRowNum To rightRowNum
            For c = leftColNum To rightColNum
                resultVal = Cells(r, c).Value
                ‘MsgBox (“(” & r & “,” & c & “) : ” & Cells(r, c).Value)
               
                ‘대상값 1번째 글자부터 textToFind 값 찾기
                idx = InStr(1, resultVal, textToFind, vbTextCompare)
                If idx > 0 Then
                    resultCount = resultCount + 1
                End If
            Next c
        Next r
       
        getCountMulti2 = resultCount
    Else
        ‘콜론이 존재하지 않는 경우(단일범위)
        resultVal = Range(cell, cell).Value
       
        ‘대상값 1번째 글자부터 textToFind 값 찾기
        idx = InStr(1, resultVal, textToFind, vbTextCompare)
        If idx > 0 Then
            resultCount = resultCount + 1
        End If
               
        getCountMulti2 = resultCount
    End If

End Function

이어지는 글 <엑셀VBA 입문 10강> VBA로 웹파싱하기 (HTML소스 가져오기)  : https://blog.naver.com/bb_/221267721181

이어지는 글 <엑셀VBA 입문 11-2강> 배열(Array) : https://blog.naver.com/bb_/221313490342

이어지는 글 <엑셀VBA 입문 12강> 특정파일 특정시트의 특정셀을 가져오는 매크로 : https://blog.naver.com/bb_/221288948784

<엑셀VBA 입문 8강> 셀 내용 가져오기

<엑셀VBA 입문 8강> 셀 내용 가져오기

오늘 배울 내용은 셀 내용을 가져오는 VBA 코드입니다.

내용은 생각보다 어려울 수 있습니다만, 제대로 배워두면 정말 도움이 되는 코드입니다.

VBA만 생각할게 아니라, 코딩의 기초를 쌓는다고 생각하면 정말 좋은 예제입니다.

(읽어보고 정 어렵다면 함수째로 복사해서 사용하면 됩니다.)

1. 셀 1개의 내용값 가져오기

아래와 같은 시트가 있다고 합시다.

B2에 “어떤 단어”라는 텍스트가 입력되어 있습니다.

이 내용을 (커서가 위치한) D6에 그대로 표시하고 싶다면 어떻게 해야할까요?

B2의 내용이 바뀔 때마다 D6의 내용도 똑같이 바뀌게 하고 싶다면 말입니다.

아시다시피 아래처럼 “=B2” 라고 입력하면 됩니다.

하지만 VBA 함수를 쓰고 싶다면요?

물론 이와 같은 경우에 굳이 VBA 함수를 쓸 필요가 없습니다만, 기본이 되는 함수를 잘 만들어두면 두고두고 유용하게 쓸 수 있습니다.

나중에 알게 됩니다.

아래와 같이 getContent라는 함수를 만들어봅니다.

매개변수가 보이시나요? 매개변수가 뭐냐고요? 참고로 매개변수란, 함수(Function) 에 넘겨줘야 하는 인자값을 말합니다. <매개변수>, <파라미터>, <인자값>, <아규먼트>… 모두 같은 말입니다. 함수는 항상 Function 함수명(매개변수1, 매개변수2, 매개변수3 …) 형태가 됩니다.

이제 매개변수가 보일겁니다. cell 이 매개변수입니다. 뒤에 As Range 라고 붙은게 있는데, 형식을 정해준겁니다. As 뒤에 붙는 이런것을 <변수형(변수의 타입)>이라고 합니다. 굳이 As Range를 붙이지 않아도 상관없지만 이렇게 명시적으로 형식을 지정해주면 장점이 2가지 있습니다. 장점 하나, 코드를 다 읽지 않아도 어떤 타입의 변수가 필요한지 알 수 있습니다. 장점 둘, 자동완성이 지원됩니다.

참고로 자동완성이란 변수 뒤에 점(.)을 찍거나, Ctrl + Space 를 누르면 나타나는 콤보박스를 말합니다. 변수형을 지정해주면 좀 더 쓸만한 자동완성이 지원됩니다. 자동완성은 제가 임의로 붙인 말이고, 영어로는 어시스트라고 부르는 것 같군요.

위의 그림이 자동완성(영어로는 어시스트)을 요약해놓은 겁니다. 한 번 읽어보시구요.

다시 getContent 함수로 돌아가보면, 아래 내용입니다.

Function getContent(cell As Range)
    resultVal = Range(cell, cell).Value
    getContent = resultVal
End Function

매개변수로 넘어온 cell 변수를 이용해서 해당 셀의 value를 가져오고 있습니다. Range(셀, 셀).Value 라는 명령어를 통해서요.

사실 실험해보시면 아시겠습니다만 Range함수는 Range(“A1”, “A1”).Value 이런식으로 쓰면 됩니다.

val = Range(“A1”, “A1”).Value 라고 쓰면 A1 셀의 내용값이 변수 val에 대입됩니다.

다만 Range(“A1”, “A2”).Value 같은 경우 먹통이 됩니다. 여러 개의 셀에는 통하지 않는거죠. 여러 개 셀의 내용(Value)를 가져오려면 코딩을 제법 해야됩니다.

2. 셀 n개의 내용값 가져오기


만약 아래와 같은 시트가 있다고 합시다.

 

여러 셀에 여러 단어가 나뉘어 입력되어 있습니다. B2 셀에 “여러”, C2 셀에 “문장을”, B3 셀에 “최대한”, B4 셀에 “합쳐 봅니다”라고 적혀있네요.

이걸 이어붙여서 한 셀에 표현하려면 어떻게 해야할까요?

엑셀 좀 하시는 분들 아실텐데 CONCATENATE 라는 함수가 있어요. 해보시면 아시겠지만 =CONCATENATE(B2, C2, B3, B4) 이런식으로 씁니다. 근데 이 함수 자체가 그다지 쓸모없어요.

저같으면 =B2 & C2 & B3 & B4 이렇게 이어버립니다. 함수 안쓰고 똑같은 효과죠.

VBA로 구현하면 조금 어렵습니다.

앞서도 말씀드렸지만 이걸 굳이 VBA로 구현할 필요가 없어보이지만, 나중을 위해 배워봅시다.

일단 셀의 값은 1개씩 가져올 수 밖에 없습니다. Range(“A1”, “A1”).Value 방식입니다. 똑같은 효과를 낼 수 있는게 Cells(1, 1).Value 라는 명령어가 있습니다. Cells(행, 열).Value 입니다. 즉, 아래와 같이 이해해보세요.

Range(“A1”, “A1”).Value 는 Cells(1, 1).Value 와 같음.

Range(“A2”, “A2”).Value 는 Cells(2, 1).Value 와 같음.

Range(“B1”, “B1”).Value 는 Cells(1, 2).Value 와 같음.

Range(“C3”, “C3”).Value 는 Cells(3, 3).Value 와 같음.

VBA에서 for문이나 do-loop 문을 돌리기 위해서는 아무래도 문자보다 숫자가 편합니다. 다시 말해서 (“A1”, “A1”) 보다는 (1, 1) 이 더 다루기 편합니다. 따라서 Cells(행, 열) 명령어를 자주 쓰게 될겁니다. 기억해두세요.

여러 셀의 내용을 가져오기 위해서는 일단 매개변수로 범위를 받아야 합니다. 엑셀의 범위는 항상 직사각형 형태를 취하는데요. 테트리스처럼 이가 빠진 모양은 될 수가 없고 항상 직사각형 모양입니다. 다시 말해서 B2 & C2 & B3 & B4 이런 범위는 없습니다. 범위는 B2:C4 이런식입니다.

이제부터 함수를 구상 해보겠습니다.

1. 매개변수로 범위를 받는다. (범위는 셀 1개일 경우 “A1” 이런식이 된다. 셀 n개일 경우 “B2:C4” 이런식이 된다)

2. 범위에 콜론(:)이 있을 경우 n개로 판단하고, 콜론(:)이 없을 경우 1개로 판단한다.

3-1. n개일 경우 직사각형 범위에 해당하는 모든 셀의 Value를 이어붙여서 리턴하자. 예컨대 범위가 B2:C4일 경우, Cells(2, 2).Value 부터 Cells(4, 3).Value 를 다 이어붙여서 리턴하자.

3-2. 1개 일 경우 1개 셀의 Value를 리턴하자. 예컨대 Range(“A1″:”A1”).Value 의 값을 리턴하자.

결과적으로 코드는 아래와 같습니다.

Function getContent(cell As Range)
    Dim resultVal
    resultVal = “”
   
    ‘addr 변수에 문자열을 저장한다. $가 포함되어 있다면 제거한다.
    ‘ex) cell.Address = “$A$1:$D$10” 이라면 addr = “A1:D10” 이 된다.
    ‘ex) cell.Address = “$A$1” 이라면 addr = “A1” 이 된다.
    Dim addr
    addr = cell.Address & “”
    addr = Replace(addr, “$”, “”)
   
    Dim colonIdx
    colonIdx = InStr(addr, “:”)
    If colonIdx > 0 Then
        ‘콜론이 존재하는 경우(다중범위)
        Dim leftAddr, leftColNum, leftRowNum
        leftAddr = Mid(addr, 1, colonIdx – 1)
        leftColNum = Range(leftAddr).Column
        leftRowNum = Range(leftAddr).Row
       
        Dim rightAddr, rightColNum, rightRowNum
        rightAddr = Mid(addr, colonIdx + 1, Len(addr) – colonIdx)
        rightColNum = Range(rightAddr).Column
        rightRowNum = Range(rightAddr).Row
       
        For r = leftRowNum To rightRowNum
            For c = leftColNum To rightColNum
                resultVal = resultVal & Cells(r, c).Value
                ‘MsgBox (“(” & r & “,” & c & “) : ” & Cells(r, c).Value)
            Next c
        Next r
       
        getContent = resultVal
    Else
        ‘콜론이 존재하지 않는 경우(단일범위)
        resultVal = Range(cell, cell).Value
        getContent = resultVal
    End If

End Function

함수가 상당히 길고 어렵다고 느낄 수 있는데, 처음엔 그럴 수 있습니다.

한 줄씩 이해하는게 가장 좋은 방법입니다. 정 어렵거나 시간이 부족하면 함수 통째로 복사-붙여넣기해다가 잘 사용하면 됩니다.

굉장히 유용한 명령어들이 많이 나오게 되는데요. 하나씩 살펴보겠습니다. 복습 차원에서 한 번 봤던 명령어도 간단히 짚고 갑니다.

1. Dim

변수를 선언하는 명령어입니다.

Dim a

a = “문자열”

이런식으로 씁니다.

2. Range형 객체의 Address 변수

(참고로 객체는, 변수와 함수를 갖고 있는 것을 말합니다. 아직은 잘 몰라도 됩니다.

Dim cell As Range 식으로 선언 하면 됩니다.)

Range형 객체의 Address 변수는 “$A$1” 이나, “$A$1:$B$2” 형태의 값을 갖고 있습니다. 예컨대 cell이 Range형 객체일 때, cell.Address 형식으로 사용합니다. 1개 셀일 때는 “$A$1” 형태의 값이고, n개 셀일 때는 “$A$1:$B$2” 형태의 값입니다.

3. &[앤드] 기호

&[앤드] 기호는 문자열 결합에 사용합니다. 숫자는 +[플러스] 기호를 써서 덧셈하는 반면, 문자열은 &[앤드] 기호로 이어붙이기를 합니다. 따라서 숫자변수 + 숫자변수는 숫자변수가 되지만, 숫자변수 & 문자변수는 문자변수가 됩니다.

참고로 &[앤드] 기호는 숫자의 문자열화(문자열로 변환) 용도로도 쓰이곤 합니다. 꼭 숫자 뿐 아니라, 문자인지 숫자인지 긴가민가한 변수를 문자열화(문자열로 변환)하는 용도로도 쓰입니다. 아래 예제를 보세요.

‘숫자변수 선언

Dim num

num = 3

‘문자열로 변환

Dim strNum

strNum = num & “”

4. Replace 함수

치환 함수. Raplace(대상문자열, 바꿀값, 새값) 형식으로 씁니다. addr = Replace(addr, “$”, “”) 이렇게 쓰면 문자열에 있는 “$”가 모두 공백으로 치환됩니다.

5. InStr 함수

위치값 계산함수. InStr(대상문자열, 찾는값) 형식으로 씁니다. 예를 들어 1이 나오면 문자열 첫번째 위치에 찾는값이 존재하는 겁니다. 1 미만(=0 이하)가 나오면 찾는값이 문자열 내에 존재하지 않는 겁니다.

6. Mid 함수

문자열 자르기 함수. Mid(대상문자열, 시작위치, 글자수) 형식으로 씁니다. 참고로 첫번째 글자의 인덱스값(위치값)이 1 입니다. 예를 들어 “대한민국”이라는 문자열이 있을 때 “대”가 인덱스 1, “한”이 인덱스 2, “민”이 인덱스 3, “국”이 인덱스 4입니다. “민국”만 자르려면 val = Mid(“대한민국”, 3, 2) 식으로 쓰면 됩니다.

상당히 헷갈릴 겁니다. 이 함수는 헷갈리는게 정상입니다. 종이나 그림판에 원고지(?) 그려가면서 천천히 살펴가면서 사용하시면 됩니다. 시간 갖고 차분히 보시면 됩니다.

7. Range(특정셀).Column

특정셀의 컬럼(열)을 숫자값으로 리턴합니다. 예를 들어 Range(“A1”).Column 의 값(컬럼값)은 1입니다.

8. Range(특정셀).Row

특정셀의 로우(행)을 숫자값으로 리턴합니다. 예를 들어 Range(“A1”).Row 의 값(로우값)은 1입니다.

9. 함수명 = 값

함수명 = 값 식으로 쓰면 값을 리턴합니다. 에를 들어 Function aaa(): aaa = “123”: End Function 이라는 함수가 있을 경우, Dim tmp: tmp = aaa() 라고 쓰면 tmp 에 “123”값이 대입됩니다.

10. Cells(행숫자, 열숫자).Value

시트의 특정 셀 값을 가져오는 코드. 예를 들어 행숫자 1에 열숫자 1일 경우 A1의 값을 가져옵니다.

결과적으로 getContent 함수를 적용하면 아래와 같은 결과를 볼 수 있습니다.

 

이어지는 글 <엑셀VBA 입문 9강> 특정 단어의 개수를 세는 방법 : https://blog.naver.com/bb_/221266831714

이어지는 글 <엑셀VBA 입문 10강> VBA로 웹파싱하기 (HTML소스 가져오기)  : https://blog.naver.com/bb_/221267721181
이어지는 글 <엑셀VBA 입문 11-2강> 배열(Array) : https://blog.naver.com/bb_/221313490342

<엑셀VBA 입문 7강> VBA 기초 명령어

<엑셀VBA 입문 7강> VBA 기초 명령어

VBA는 엑셀에 내장되어 있는 프로그래밍 언어다. VBA 공부는 기본적으로 코딩 공부다.

VBA를 잘 사용하기 위해선 기초 명령어들을 잘 배워둬야 한다. 물론 잘 모른다고 VBA를 사용할 수 없는건 아니다. (눈치 봐서 적당히 가져다 쓰면 된다. Copy And Paste. 일명 복붙.)

이번에는 VBA 기초 명령어를 소개한다.

VBA 기초 명령어는 C, JAVA, 파이썬 등의 기초 명령어와 그다지 다르지 않다. 즉 기존에 프로그래밍을 할줄 안다면 좀 더 편하게 접근할 수 있다.

프로그래밍의 프 자도 모른다고? 괜찮다. 반대로 얘기하면 VBA 기초 명령어를 배워두면 다른 개발 언어를 배울 때 큰 도움이 된다. 언어란게 다 그렇다.

1. 변수

명령어를 알기 전 개념을 다시 짚고 넘어가자. 변수는 가장 중요한 개념 중의 하나다.

변수란 값을 저장하는 공간이다. 흔히들 변수를 상자(Box)에 비유한다. a라는 이름의 상자를 마련했다고 치자. 이를 변수의 선언이라고 한다. Dim a 라고 쓰면 변수 a가 선언된 것이다.

a라는 이름의 상자에 10 이라는 숫자값을 넣는다고 상상해보자. 이를 변수의 대입이라고 한다. a = 10 라고 쓰면 이제 a는 10 이라는 값을 저장한다. 앞으로 a 를 출력하면 10 을 출력한다.

변수는 가진 값을 더할 수도 있고 뺄 수도 있다. 기본적인 사칙연산이 다 가능하다. 더하기는 + 로, 빼기는 – 로, 곱하기는 * [별]로, 나누기는 / [슬래시]로, 나눠서 나머지 구하기는 mod[모드] 라는 명령어로 한다. 예를 들어 a = a + 2 라고 쓰면 기존 a값에 2를 더한 값이 a에 저장된다. 프로그래밍에서 등호(=)는 좌측으로 대입한다는 뜻으로 외우는게 편하다. a = x 는 a ← x 와 다름 없다.

숫자는 사칙연산을 쓰지만, 문자열은 어떻게 더할까? 문자열은 &[앤드] 기호를 이용해 결합할 수 있다. 정리하면 아래와 같다.

‘변수의 선언
Dim a

‘변수의 대입
a = 10  ‘이제 a는 10

‘변수의 사칙연산
a = a + 2  ‘이제 a는 12
a = a – 4  ‘이제 a는 8
a = a * 2  ‘이제 a는 16
a = a / 4  ‘이제 a는 4
a = a mod 3 ‘이제 a는 1

‘다른 변수의 선언
Dim str

‘변수의 대입(문자열)
str = “문자”

‘문자열 변수의 결합
str = str & “열”  ‘이제 str은 “문자열”

2. 함수

함수란 입력값을 넣으면 어떤 규칙에 의해 출력값을 되돌려주는 것을 의미한다. 다만 입력값이 없거나, 출력값이 없는 함수도 있다. 입력값이 없는 함수는 입력값 자체가 필요없거나, 전역변수(프로그램 어디에서나 사용하는 변수)를 입력값으로 삼는 경우다. 출력값이 없는 함수는 역시 출력값이 필요없거나, 전역변수에 어떤 값을 대입함으로써 함수의 출력값 없이 끝나는 경우다.

함수는 기본적으로 아래 형태로 작성한다.

Function 함수명(입력변수1, 입력변수2 … )
    ‘결과변수 선언
    Dim result

    ‘내용
    (중략)
   
    ‘결과변수 리턴
    함수명 = result
End Function

3. 주석

주석은 프로그램 실행에 아무런 영향을 주지 않는 문자열들이다. 대개 참고사항을 적는 용도로 사용한다.
VBA는 문자열 앞에 홑따옴표(‘)를 붙이면 홑따옴표 포함하여 이후 모두 주석처리 된다.

‘1줄 주석
Dim temp ‘여기서부터 또 주석

3. MsgBox


MsgBox(문자열) 명령어 쓰면 작은 알림창을 띄워준다.
디버그(프로그램 오류를 없애는 작업)를 위해 변수값을 확인하는 용도로도 많이 쓰고, 사용자에게 상황을 알리기 위해 많이 쓴다.

예는 아래와 같다.

Dim result
result = 3

MsgBox(“헬로 월드”)
MsgBox(“테스트 결과 : ” & result)

4. InputBox

InputBox(문자열) 명령어 쓰면 기본적인 입력창을 띄워준다. 사용자의 입력값을 변수로 저장시키기 위한 함수다.

Dim myName
myName = InputBox(“이름을 적어주세요.”)

MsgBox(“myName : ” & myName)

5. If

If문은 모든 프로그램의 기본이 되는 명령어다. If 조건 Then 내용 End If 식으로 사용한다.
여러 조건을 체크하기 위해서는 ElseIf문을 사용하고, 어떤 조건도 충족되지 않은 경우는 Else문을 사용한다.
아래 예제 코드를 보면 이해하기 쉬울 것이다.

5-1. 기본 If문
If 조건 Then
    ‘조건 충족시 수행
End If

5-2. ElseIf의 사용
If 조건1 Then
    ‘조건1 충족시 수행

ElseIf 조건2 Then
    ‘조건2 충족시 수행

ElseIf 조건3 Then
    ‘조건3 충족시 수행

End If

5-3. Else의 사용
If 조건1 Then
    ‘조건1 충족시 수행

ElseIf 조건2 then
    ‘조건2 충족시 수행

Else
    ‘어떤 조건도 충족하지 못했을 경우 수행

End If

6. For
For문도 아주 중요한 명령어에 해당한다. 처음에는 명령어 자체가 헷갈리곤 하는데, 처음 사용할 때는 깊게 고민하기보다 통째로 외우는 편이 좋다.

For 변수명 = 시작인덱스 To 종료인덱스
    ‘수행할 내용
Next 변수명

보통 For문의 변수명은 i를 사용하며, index의 약자로 추정된다. For문 내부의 내용은 여러번 반복되는데, 시작인덱스가 종료인덱스가 될 때까지 반복 수행한다.

한마디로 For i = 1 To 10 이라고 쓰면 For문 내부를 10번 반복한다.
아래는 예제 코드다.

‘메시지를 10번 띄우는 코드
For i = 1 To 10
    MsgBox (i & “번째 메시지”)
Next i

‘For문의 반복횟수를 변수로 조절하기
Dim beginIdx
Dim endIdx
beginIdx = 1
endIdx = 10

For i = beginIdx To endIdx
    MsgBox (i & “번째 메시지”)
Next i

‘중첩 For문 사용 해보기. 흔히 “이중포문”이라 불린다.
For i = 1 to 3
    For j = 1 to 3
        ‘(1,1), (1,2), (1,3), (2,1), …, (3,3) 식으로 메시지 순차적으로 띄워줄것
        MsgBox (“(” & i & “,” & j & “)”)
    Next j
Next i

7. Do ~ Loop 

Do문은 특정 조건에 만족하는한 계속 반복되는 함수다. 자칫 잘못하면 절대 끝나지 않는 반복의 늪에 빠지게 되는데, 이를 흔히 “무한루프에 빠졌다”라고 표현한다.

사실 For문과 Do문은 엄밀히 따졌을 때 같은 기능의 함수다. 실제로 For문은 언제든지 Do문으로 바꿔쓸 수 있고, 반대의 경우도 마찬가지다.

상황에 따라 편한대로 For문을 쓰든 Do문을 쓰든 선택하면 된다.

아래와 같이 사용한다.

Do
    ‘반복 수행할 내용

    ‘루프 나가기 (반드시 있어야 하는 부분)
    If 조건 Then
        ‘Do 문을 빠져나간다.
        ‘조건을 충족하지 못하면 무한루프에 빠진다.
        Exit Do
    End If

Loop

참고로 무한루프에 걸렸다면 Ctrl + Break 키를 누르면 빠져나간다. Break는 보통 키보드 최상단 우측 편에 위치한다.

8. Left, Right, Mid

문자열을 잘라내는 함수다. Left를 쓰면 왼쪽부터 특정 글자수만큼 잘라내고, Right를 쓰면 오른쪽부터 특정 글자수만큼 잘라낸다.
Mid를 쓰면 문자열 중간부터 잘라낼 수 있는데, 사실 Left와 Right 함수 양쪽을 대체할 수 있다.

Left(문자열, 좌측부터 잘라낼 글자수)
Right(문자열, 우측부터 잘라낼 글자수)
Mid(문자열, 잘라내기 시작할 글자번호) 또는 Mid(문자열, 잘라내기 시작할 글자번호, 글자수)

예를 들면 아래 코드와 같다.

Dim str = “문자열”
Dim result

result = Left(str, 1)  ‘result 값은 “문”
result = Right(str, 1)  ‘result 값은 “열”
result = Mid(str, 1)  ‘result 값은 “문자열”
result = Mid(str, 2)  ‘result 값은 “자열”
result = Mid(str, 2, 1)  ‘result 값은 “자”


9. InStr 

 

특정한 문자열 안에 또다른 특정한 문자열이 몇 번째 글자에 위치하는지 얻어내는 함수.
문자열의 완전일치가 아니라 부분포함 관계를 찾는다는 점에서 여러모로 유용한 함수다.

InStr(찾기 시작할 글자번호, 대상 문자열, 찾는 문자열, vbTextCompare)

예를 들면 아래 코드와 같다.

Dim a
a = InStr(1, “문자열 대상”, “문자”, vbTextCompare)  ‘a값은 1
a = InStr(1, “문자열 대상”, “자”, vbTextCompare)  ‘a값은 2
a = InStr(1, “문자열 대상”, “없는단어”, vbTextCompare)  ‘a값은 0

반드시 필수라고 생각하는 명령어만 모아두었다. 기본적으로 이 정도 기억하고 VBA에 접근하는 것과, 그렇지 않은 것은 천지차이일 것이라 생각한다.

이어지는 글 <엑셀VBA 입문 8강> 셀 내용 가져오기 : https://blog.naver.com/bb_/221260814900

이어지는 글 <엑셀VBA 입문 9강> 특정 단어의 개수를 세는 방법 : https://blog.naver.com/bb_/221266831714

이어지는 글 <엑셀VBA 입문 10강> VBA로 웹파싱하기 (HTML소스 가져오기)  : https://blog.naver.com/bb_/221267721181

<엑셀VBA 입문 6강> VBA 저장하는 법

<엑셀VBA 입문 6강> VBA 저장하는 법

오늘은 쉽지만 무척 중요한 내용이다. VBA 저장하는 법이다.

“VBA 코드는 다 짰어. 그런데 이거 어떻게 저장하지?”라는 생각이 들 때가 됐다.

엑셀은 대표적으로 2가지 확장자를 제공한다. xls와 xlsx가 그것이다. xls는 엑셀 97부터 2003 버전까지 사용하는 확장자다. 이후 버전은 xlsx로 저장된다. 말인즉슨 우리가 엑셀 파일이라고 부르는 것은 xls와 xlsx, 둘 중 하나라고 봐도 무방하다.

<엑셀은 다양한 확장자를 제공한다. 그 중에서도 xls와 xlsx가 대표격이다>

열심히 VBA(매크로)를 작성하고 엑셀을 저장하려면 아래와 같은 메시지가 뜬다.

“다음 기능은 매크로 제외 통합 문서에 저장할 수 없습니다.

– VB 프로젝트

이러한 기능이 포함된 파일을 저장하려면 [아니요]를 클릭한 다음 [파일 형식] 목록에서 매크로 사용 파일 형식을 선택하십시오.

매크로 제외 통합 문서로 계속 저장하려면 [예]를 클릭하십시오.”

<VB 프로젝트를 저장하기 위해선 매크로 사용 파일 형식을 선택하라는 메시지가 뜬다>

살펴보면 확장자에는 xls와 xlsx만 있는게 아니라, xlsm이라는게 있다. “Excel 매크로 사용 통합 문서(*.xlsm)”이라고 한다. 이 파일 형식으로 선택하면 엑셀과 매크로를 파일 하나로 저장할 수 있다. 결론부터 밝히자면 xlsm 확장자 1번, xlsx 확장자로 1번, 총 2번 저장하기를 권한다.

개인 백업용으로 USB에 넣거나, 자기 자신에게 메일을 보내는 차원이라면 xlsm 파일로만 저장해도 상관없다. 작업중인 파일도 물론 xlsm로 저장하는게 편하다. 하지만 남에게 파일을 전송하는 경우 xlsx파일로 저장해서 보내기를 권장한다. xlsm 파일은 엑셀 버전에 따라 오픈할 때 경고 메시지가 뜨기도 하고, 메일 첨부시에 바이러스성 파일로 분류되기도 한다. VBA라고 표현하든 매크로라고 표현하든, 기본적으로 프로그램이다. 받아보는 사람 입장에서는 불안하게 느낄 수 있다.

그럼에도 불구하고 일단 xlsm파일로 저장해두라는 것은 자칫 실수로 애써 만든 VBA 코드를 날려버릴 수 있기 때문이다. 일단 매크로 포함 xlsm 파일로 저장하고, xlsx파일로 다른 이름으로 저장하여 업무에 활용하면 된다.

기타 알아두면 좋은 팁으로는 매크로/VBA만 따로 저장하는 방법이 있다. 바로 VBA 모듈 저장이다.

* VBA 모듈 저장하는 방법

1. Alt + F11 키를 눌러 VBA 윈도우를 띄운다.

2. 생산한 모듈(ex: Module1) 파일 위에서 마우스 우클릭하고 [파일 내보내기]를 선택한다. (혹은 상단 메뉴의 [파일] – [파일 내보내기] 메뉴를 선택한다.)

3. 적당한 위치에 저장한다. (확장자 bas 파일이 저장된다.)

<VBA 모듈을 저장하는 법. 내보내기 하면 세이브하고, 가져오기로 로드할 수 있다>

VBA 모듈을 불러오는 방법도 쉽게 알 수 있다.

* VBA 모듈 불러오는 방법

1. Alt + F11 키를 눌러 VBA 윈도우를 띄운다.

2. [모듈] 폴더 위에서 마우스 우클릭하고 [파일 가져오기]를 선택한다. (혹은 상단 메뉴의 [파일] – [파일 가져오기] 메뉴를 선택한다.)

3. 미리 저장해둔 확장자 bas 파일을 선택한다.

VBA 모듈을 저장하고 불러오는게 별거 아닌 기술 같지만 상당히 유용하다. 예를 들어 특정 함수에 단축키를 지정해뒀다면(대표적으로 VBA 매크로일 경우) 모듈을 가져다 쓴 엑셀에서도 동일한 단축키로 함수를 실행시킬 수 있다.

만약 수식입력줄에 사용할 수 있게 여러가지 함수를 만들어놓은 상태라면, 다음에 새 엑셀 파일을 작성할 때에도 편리하게 재사용할 수 있다. 유용한 함수들을 여러개 모아둔 것을 한 단어로 라이브러리라고 하는데, VBA 작성에 있어서도 어느 정도 라이브러리를 만들어놓으면(함수를 여러개 개발해서 잘 정리해놓으면) 시간이 지날수록 편하게 개발할 수 있다.

개인적으로는 수식입력줄에 사용 가능한 VBA 함수 만들기는 크게 선호하지 않는다. xlsx 파일로 전송했을 때 모듈까지 동봉해서 제공하지 않는한 수식이 깨질 위험이 있다. 그래서 단축키가 걸린 매크로(ex: Ctrl + K)가 상당히 유용하다. 단축키가 걸린 매크로는 대부분의 경우가 셀에 수식을 넣는게 아니라 값 자체를 바꾸는 식으로 만들어지기 때문에, 모듈이 없어져서 데이터가 깨지지 않을까 염려하지 않아도 된다.

이어지는 글 <엑셀VBA 입문 7강> VBA 기초 명령어 : https://blog.naver.com/bb_/221253767009

​이어지는 글 <엑셀VBA 입문 8강> 셀 내용 가져오기 : https://blog.naver.com/bb_/221260814900
이어지는 글 <엑셀VBA 입문 9강> 특정 단어의 개수를 세는 방법 : https://blog.naver.com/bb_/221266831714

<엑셀VBA 입문 5강> 특정 단어를 포함하는지 확인하는 함수

<엑셀VBA 입문 5강> 특정 단어를 포함하는지 확인하는 함수

엑셀에서 가장 많이 사용하는 함수가 SUM[썸], COUNT[카운트]라면, 그 다음으로 많이 사용하는 함수는 SUMIF[썸이프], COUNTIF[카운트이프]가 될 것이다.

어째서일까? IF는 분류를 위한 함수다. 어떤 업무를 하든지 분류 작업이 필수다. 우리에게는 데이터를 분류하고 분류별로 계산하고자 하는 니즈가 있다.

쇼핑몰을 하고 있다면 와이셔츠의 수량, 청바지의 수량을 세어보게 되어있다. 설문조사를 하고 있다면 지역별 분류가 필요하다. 고객 문의를 접수하고 있다면 단순 상담인지 신규 가입인지, 탈퇴 요청인지 클레임인지 구분해야 한다.

또 하나 엑셀에 유명한 함수가 있다면 VLOOKUP[브이룩업]을 들 수 있다. 일반적으로 SUM, SUMIF, MID/LEFT/RIGHT, VLOOKUP이면 웬만한 엑셀 업무는 처리할 수 있다. VLOOKUP 역시 분류에 따른 특정값의 반환이 목표다. (참고로 VLOOKUP 함수를 몰라도 이 글을 읽는데는 지장이 없다)

하지만 SUMIF, COUNTIF, VLOOKUP에는 치명적 약점이 있다. 정확한 값을 요구한다는 점이다. 청바지의 수량만 더하고자할 때 COUNTIF는 특정값(ex: “청바지”)을 찾는다. “청바지”라는 단어를 포함하는 경우는 찾지 않는다.

다음은 서울이라는 단어가 포함될 경우 O를 기입, 포함되지 않을 경우 X를 기입하는 예제다.

서울이라는 단어가 포함되어 있을 경우 O를 기입, 그렇지 않으면 X를 기입했다. 여기서는 함수를 쓰지 않고 직접 입력했다. 항목 4개 정도는 사람이 기입할 수 있다. 하지만 4만 개라면 어떨까?

다행히 특정 단어를 포함하는지 확인하는 함수는 기존 엑셀에 존재한다. SEARCH 함수다. SEARCH(찾을문자, 대상텍스트) 식으로 사용한다.

=SEARCH(찾을문자, 대상텍스트)

ex) =SEARCH(“서울”, A1)

보다시피 특정 단어가 n번째 글자에 위치할 경우 n을 반환하고 있다. 다만 SEARCH 함수의 특징은 특정 단어를 찾아내지 못했을 경우 #VALUE! 에러를 뱉어낸다는 점이다. 그렇기에 SEARCH 함수는 항상 IF함수와 ISERROR 함수를 동원해 아래와 같이 사용하곤 한다.

=IF(ISERROR(SEARCH(찾을문자, 대상텍스트)), 0, SEARCH(찾을문자, 대상텍스트))

ex) =IF(ISERROR(SEARCH(“서울”, A1)), 0, SEARCH(“서울”, A1))

다소 복잡해보인다. 원래 남이 짠 코드는 복잡해보이는게 정상이니 인내심을 갖자. IF함수를 동원해서 SEARCH가 에러를 뱉을 경우 0 을 표현하고, 그렇지 않을 경우 SEARCH 의 반환값을 보여주는 명령어다. 즉, 결과값이 0 이면 특정 단어가 미포함 상태이고 결과값이 1 보다 크거나 같으면 포함 상태이다.

만약 VBA를 이용해 이러한 함수를 직접 만들어보면 어떨까? 방법은 아래와 같다.

1. 엑셀을 켠다.

2. Alt + F11 키를 눌러 VBA를 켠다.

3. 상단 메뉴의 [삽입] – [모듈] 클릭한다. 모듈 창이 뜬다.

4. 아래와 같이 코드를 입력한다.

Function indexOf(cell, textToFind)

    ‘cell의 값을 가져옴
    Dim val
    val = Range(cell, cell).Value

    ‘cell의 값 1번째 글자부터 textToFind 값 찾기
    Dim idx
    idx = InStr(1, val, textToFind, vbTextCompare)

    ‘인덱스 값을 리턴
    indexOf = idx

End Function

5, 엑셀 시트에서 indexOf(대상텍스트, 찾을문자) 로 함수를 사용해보자.

ex) =indexOf(A1, “서울”)

 

이런식으로 하면 =IF(ISERROR(SEARCH(찾을문자, 대상텍스트)), 0, SEARCH(찾을문자, 대상텍스트)) 라는 함수를 indexOf라는 한 단어의 함수로 줄여 사용할 수 있다.

물론 VBA 코드를 이해하는게 처음에는 쉽지 않을 것이다. 가급적 “쉬운 것인데 왜 이해를 못하지”라고 생각하지 말고, “정말 어렵고 가치있는 것이므로 이해하지 못하는게 당연하다”고 받아들이길 바란다.

먼저 VBA에는 내장함수로 InStr이라는 함수가 있다. “InStr(1, val, textToFind, vbTextCompare)” 이라는 명령어는 “문자찾기(1번째글자부터, 대상텍스트, 찾을문자열, 텍스트비교)”라는 의미로 받아들이면 된다. InStr의 리턴값은 찾아낸 글자위치이다. 예를 들어 찾는 값을 대상 텍스트의 첫 번째 글자에서 찾았다면 숫자 1을 리턴하고, 문자를 찾지 못하면 0 을 리턴한다.

함수 내용을 풀어보자면 먼저 첫번째인자로 넘어온 셀의 값(cell)을 변수 val에 담고, VBA 내장함수인 InStr을 이용해서 cell의 값 내부에서 두번째 인자(textToFind)의 위치를 찾는다. 이후 결과값(위치값)을 변수 idx에 담고, 그대로 리턴한다.

만약 포함하는지를 O, X로 표현하고 싶다면 include 라는 함수로 변형해서 사용할 수도 있다. 다음은 그 예다.

Function include(cell, textToFind)

    ‘cell의 값을 가져옴
    Dim val
    val = Range(cell, cell).Value

    ‘cell의 값 1번째 글자부터 textToFind 값 찾기
    Dim idx
    idx = InStr(1, val, textToFind, vbTextCompare)

    ‘인덱스 값을 리턴
    If idx > 0 Then
        include = “O”
    Else
        include = “X”
    End If

End Function

 

이렇게 이번 강의에서는 include라는 이름의 특정 단어를 포함하는지 확인하는 함수를 만들어보았다. 내용상으로는 앞서 만든 indexOf에 비해 큰 차이가 없다. 내용 중에 익숙한 함수명이 보일텐데, 그 이름도 유명한 IF[이프]다. VBA에서 IF문은 다음과 같이 사용한다.

1. IF문 첫 번째

If 조건 Then

    ‘조건 충족시 실행할 내용

End If

2. IF문 두 번째

If 조건 Then

    ‘조건 충족시 실행할 내용

Else

    ‘조건미충족시 실행할 내용

End If

3. IF문 세 번째

If 조건1 Then

    ‘조건1 충족시 실행할 내용

Else If 조건2 Then

    ‘조건2 충족시 실행할 내용

End If

4. IF문 네 번째

If 조건1 Then

    ‘조건1 충족시 실행할 내용

Else If 조건2 Then

    ‘조건2 충족시 실행할 내용

Else If 조건3 Then

    ‘조건3 충족시 실행할 내용

Else

    ‘모든 조건 미충족시 실행할 내용

End If

간단하게나마 VBA 코드를 다루고자 한다면 간단한 내장함수들은 사용법을 익혀둬야 한다. 함수 사용법을 일부러 외울 필요는 없고 나중에라도 인터넷 검색을 통해 어떻게 사용했는지 떠올려볼 수 있으면 된다. 아니면 적당히 복사-붙여넣기를 통해 코드를 짜도 된다. 시험 공부는 컨닝이 허용되지 않지만 업무는 아무래도 상관없다. 일만 잘하면 장땡이다.

기회가 닿는대로 VBA 함수를 다룰 예정이지만 함수 하나하나를 자세히 설명하기는 곤란하다. 자꾸 보면 자연스럽게 이해가 되는 날이 올 것이다. 대표적인 VBA 내장함수는 If, MsgBox, For, Do 문 등이 있다. 차차 배울 수 있을 것이다.

이어지는 글 <엑셀VBA 입문 6강> VBA 저장하는 법 : https://blog.naver.com/bb_/221253136556

이어지는 글 <엑셀VBA 입문 7강> VBA 기초 명령어 : https://blog.naver.com/bb_/221253767009
이어지는 글 <엑셀VBA 입문 8강> 셀 내용 가져오기 : https://blog.naver.com/bb_/221260814900

<엑셀VBA 입문 4강> 수식 입력줄에서 함수 실행하기

<엑셀VBA 입문 4강> 수식 입력줄에서 함수 실행하기

엑셀은 기본적으로 함수를 제공하고 있다. 우리가 아는 sum, sumif, count, counta 등이 기본함수다. 그런데 추가적으로 사용자가 원하는 함수를 새로 만들어 사용할 수 있다. 함수를 만드는 방법은 크게 3가지가 있다.

함수 만드는 방법 3가지

(1) 단축키로 실행 (매크로)
(2) 버튼을 클릭해서 실행
(3) 수식 입력줄에서 실행

이번에는 3번 방식을 배워본다.

1. 엑셀을 실행하고, Alt+F11 키를 눌러 VBA 윈도우를 연다. 좌측 프로젝트 탐색기에서 [VBAProject] 항목에서 마우스 우클릭 – [삽입] 선택 – [모듈] 클릭한다.

 

2. 좌측 프로젝트 탐색기에서 [Module1 ]을 더블클릭하여 함수를 만들어본다. 처음에 Module1의 내용은 텅 비어있을 것이다. 아래와 같이 내용을 쓴다.

Function getValue()

    getValue = “새 값”

End Function

포인트는 이전과 다르게 “Sub 함수명() ~ End Sub”가 아니라 Function 이라는 단어를 쓴다는 점이다. “Function 함수명() ~ End Function” 으로 함수를 만들면 엑셀 수식 입력줄에서 바로 사용가능한 사용자 정의 함수가 된다.

함수는 특정한 입력값(인풋)을 넣으면 일정한 규칙에 따라 출력값(아웃풋)을 되돌려주는 것을 의미한다. 여기서 getValue라는 함수의 경우 입력값은 없고, 출력값이 “새 값”이다. 다시 말해, “함수명 = 값” 은 해당 함수의 출력값을 결정하는 명령어다. 이해가 잘 안될 수 있는데 쓰다보면 알게되니 걱정말고 넘어가도 좋다.

3. VBA 윈도우를 끄고(엑셀을 종료해선 안됨), 엑셀 시트의 아무곳에나 =getValue() 라는 함수를 입력해본다. 직접 만든 함수를 이렇게 사용할 수 있다.


 

이 경우 아래와 같이 “새 값”이라는 결과가 나타나는 것을 볼 수 있다. 이제 다시 한 번 VBA 코드를 보면 조금 더 이해하기 쉬울 것이다.

 

4. 조금 욕심을 부려서 함수의 내용을 개선해보자. 아래와 같이 내용을 입력해보자.

Function getValue(cell)

    Dim val
    val = Range(cell, cell).Value
   
    getValue = val
   
End Function

함수의 내용을 간단히 설명하자면, 첫번째 인자로 입력된 셀(ex: A1)의 내용을, 현재 선택한 셀 내용에 입력시키는 것이다. 쉽게 말해 특정셀의 내용을 그대로 가져오는게 이 함수의 내용이다.

잘 이해가 되지 않더라도 결과부터 살펴보도록 하자. 아래와 같이 getValue에 1개의 인자를 넣어 사용한다.

아래와 같이 특정셀의 내용을 그대로 가져오게 된다.

처음부터 VBA 코드를 잘 이해할 수 있다면 좋겠지만, 배우지 않았다면 잘 모르는게 정상이다. 위 VBA 코드를 이해하기 위해서는 변수, 그리고 함수에 대해서 배워야 한다.

5. 함수 이해하기

함수란 입력값을 넣으면 일정한 규칙에 따라 출력값을 되돌려주는 것이다. “Function 함수명(인자값1, 인자값2, …) ~ End Function” 식으로 쓴다. 예제로 등장한 getValue 함수의 경우, 입력값은 1개(cell) 이라고 볼 수 있다.

출력값은 val이다. “함수명 = 값”(ex: getValue = val) 의 형태를 보면 알 수 있다.

그렇다면 입력값과 결과값은 필수인가? 둘 다 필수는 아니다. 입력값이 없는 함수를 만들고 싶다면 인자 없이 “Function 함수명() ~ End Function” 식으로 코딩하면 된다. 결과값(리턴)이 없는 함수도 허용된다.

다만 단축키로 실행(ex: Ctrl + k) 하는 함수의 경우 리턴값이 없는 경우가 많고, 수식 입력줄에서 사용하는 경우 리턴값이 있는 경우가 일반적인 것 같다.

6. 변수 이해하기

중요한 명령어가 나오는데 Dim 이다. 변수를 선언할 때 쓰는 명령어다. 프로그래밍에서 변수란 아주 중요한 개념이므로, 잘 모르고 있다면 여기서 반드시 이해하고 넘어가자.

Dim 은 변수를 선언하는 명령어다. “Dim 변수명” 식으로 쓴다. 그렇다면 변수란 무엇인가? 프로그래밍을 처음 배울 때 변수를 “상자(Box)”라고 생각하라고들 하는데, 괜찮은 설명이라고 생각한다. 변수란 어떤 값(데이터)를 저장해두는 상자라고 생각하면 편하다. 예를 들어 aa라고 이름 붙여진 상자를 생각해보자.

dim aa

dim aa 라고 쓰면 aa라는 변수(상자)가 만들어지게 된다.

aa = 2

이제 aa라는 변수(상자)에는 2라는 값이 담겨졌다. MsgBox(aa) 를 실행하면 메시지박스에 2라는 값이 표시될 것이다. 참고로 프로그래밍의 등호(=)는 “같다”는 뜻이 아니다. 프로그래밍의 등호(=)는 “우측값을 좌측변수에 대입한다”는 뜻으로, 기호로 표현하면 “←”에 가깝다.

aa = 2 + 1

이제 aa라는 변수의 값은 3이 된다.

aa = aa + 3

이번에는 기존 aa값에 따라 결과값이 달라질 것이다. 기존값이 3이라면 답은 6이 된다.

정리하자면,

Dim aa

aa = 2

aa = 2+1

aa = aa + 3

MsgBox(aa)

라고 실행했을 때 메시지 박스에는 6이라는 숫자가 표시될 것이다.

7. getValue(cell) 함수의 이해

함수 각 라인마다 주석을 달아 설명해보자면 다음과 같다. 참고로 주석이란 VBA에서 홑따옴표(‘)로 표시하며, 홑따옴표(‘) 뒤쪽의 텍스트는 코드의 실행에 영향을 끼치지 못하도록 무시된다. 주석은 소스코드로 표현하지 못하는 참고사항을 적는 용도로 쓴다.

Function getValue(cell)

    Dim val ‘val 이라는 이름의 변수를 선언한다.
    val = Range(cell, cell).Value ‘Range(cell, cell).Value 는 특정 셀 한 칸의 값을 가져온다.

    ‘참고 : ‘Range(셀1, 셀2) 함수는 영역을 지정한다. 여기서는 셀1과 셀2가 같으므로, cell 한 칸이 된다. 
    
    getValue = val ‘val을 리턴한다(결과값 삼는다).
   
End Function

5강에서는 VBA 기초 명령어를 배우고 계속해서 함수를 만들어보도록 하자.

이어지는 글 <엑셀VBA 입문 5강> 특정 단어를 포함하는지 확인하는 함수 : https://blog.naver.com/bb_/221249954442

이어지는 글 <엑셀VBA 입문 6강> VBA 저장하는 법 : https://blog.naver.com/bb_/221253136556

이어지는 글 <엑셀VBA 입문 7강> VBA 기초 명령어 : https://blog.naver.com/bb_/221253767009

<엑셀VBA 입문 3강> 버튼 클릭하면 실행되는 함수 만들기

<엑셀VBA 입문 3강> 버튼 클릭하면 실행되는 함수 만들기

엑셀은 기본적으로 함수를 제공하고 있다. 우리가 아는 sum, sumif, count, counta 등이 기본함수다. 그런데 추가적으로 사용자가 원하는 함수를 새로 만들어 사용할 수 있다. 함수를 만드는 방법은 크게 3가지가 있다.

함수 만드는 방법 3가지

(1) 단축키로 실행 (매크로)
(2) 버튼을 클릭해서 실행
(3) 수식 입력줄에서 실행

여기서 2번 방식을 배워보자.

1. 엑셀을 켜고 상단의 [삽입] 탭 – [도형] 선택 – [모서리가 둥근 직사각형]을 선택하고 엑셀 상에 적당한 크기로 그려넣는다. 내부 텍스트값은 CLICK이라고 쓴다. 지금부터 이 도형을 버튼이라고 생각하자.

2. 새로 만든 도형(버튼) 위에서 마우스 우클릭하여 [매크로 지정]을 선택한다. [매크로 지정] 윈도우가 뜨면 [새로 만들기] 버튼을 클릭한다. 버튼에 매크로 함수를 연결하는 과정이라 이해하면 된다.

3. VBA 윈도우(Microsoft Visual Basic For Applications의 약자)가 뜰 것이다. “모서리가둥근직사각형1_Click” 이라는 함수가 만들어져있을 것이다. 참고로 “Sub 함수명” 이 함수의 시작이고, “End Sub”가 함수의 끝이다. 여기서 함수명은 중요하지 않으므로, “모서리가둥근직사각형1_Click”이 아니어도 관계없다. 함수 내용부에 MsgBox(“Click Event”) 라고 입력해넣는다.

 

4. VBA 윈도우를 닫는다(엑셀을 닫아선 안됨). Click 버튼을 누르면 “Click Event”라는 내용의 메시지 박스가 뜰 것이다. MsgBox 명령어는 자주 쓰이므로 기억해두는게 좋다.

5. 함수 내용을 조금만 더 발전시켜보자. Alt+F11 키를 누르면 VBA 윈도우가 뜬다. 좌측의 Module1을 더블클릭하여 아까 만든 함수를 열어보자. 함수 내용을 ActiveCell.Offset(0, 0).Value = “현재 셀에 내용입력” 으로 수정해보자.

 

6. 아무 셀이나 빈 셀을 선택해둔 상태에서, Click 버튼을 눌러보자. 선택한 셀의 내용이 “현재 셀에 내용입력”으로 바뀔 것이다.

상당히 유용한 명령어가 등장했는데, ActiveCell.Offset(0, 0).Value 다. 해석하자면 “현재셀.위치조정(0,0).값”이라는 의미다. 응용해서 쓸만한 명령어를 몇 가지 만들어보면 다음과 같다.

ActiveCell.Offset(0, 0).Value = “특정내용”

=> 현재 셀에 “특정내용”을 입력한다.

MsgBox (“value : ” & ActiveCell.Offset(0, 0).Value)

=> 현재 셀의 내용을 메시지 박스로 띄운다.

ActiveCell.Offset(0, 0).Value = ActiveCell.Offset(0, 0).Value & “원”

=> 현재 셀 내용 뒤쪽에 “원”이라는 글자를 붙인다.

ActiveCell.Offset(0, 0).Value = “\” & ActiveCell.Offset(0, 0).Value

=> 현재 셀 내용 앞쪽에 “\”이라는 글자를 붙인다.

ActiveCell.Offset(0, 0).Value = ActiveCell.Offset(1, 0).Value

=> 현재 셀에 바로 아래칸의 셀 내용을 입력한다.

ActiveCell.Offset(0, 0).Value = ActiveCell.Offset(-1, 0).Value

=> 현재 셀에 바로 위칸의 셀 내용을 입력한다.

ActiveCell.Offset(0, 0).Value = ActiveCell.Offset(0, 1).Value

=> 현재 셀에 바로 우측칸의 셀 내용을 입력한다.

ActiveCell.Offset(0, 0).Value = ActiveCell.Offset(0, -1).Value

=> 현재 셀에 바로 좌측칸의 셀 내용을 입력한다.

잘 정리해두면 나중에 엄청나게 도움이 되는 명령어 시리즈다.

4강에서는 수식 입력줄에서 실행하는 함수를 만들어 본다.

이어지는 글 <엑셀VBA 입문 4강> 수식 입력줄에서 함수 실행하기 : https://blog.naver.com/bb_/221249107922

이어지는 글 <엑셀VBA 입문 5강> 특정 단어를 포함하는지 확인하는 함수 : https://blog.naver.com/bb_/221249954442
이어지는 글 <엑셀VBA 입문 6강> VBA 저장하는 법 : https://blog.naver.com/bb_/221253136556

윈도우10에서 아파치 웹서버 세팅

윈도우10에서 아파치 웹서버 세팅

출처 : http://jimnong.tistory.com/612

상기 출처의 내용을 그대로 요약하였다. 자세한 내용은 상기 출처에 더 잘 나와있다.

(옮겨적는 이유는 해당 블로그가 심각하게 느려서 도저히 천천히 읽어볼 수가 없을 정도다. 자세한 이유는 모르겠음)

아파치 웹서버를 윈도우10에 세팅하는 이유는 개발 실습을 위해서다. 실전에서는 리눅스에 띄워야 하겠다.

아래는 성공했을 경우 화면

1. https://www.apachelounge.com/download/ 에 접속해서 Apache 2.4.33 Win64 : httpd-2.4.33-win64-VC15.zip 를 다운받는다.

2. 압축을 풀고 Apache24 폴더를 C:\Apache24 에 위치시킨다.

3. C:\Apache24\conf\httpd.conf 파일을 편집한다.

3-1. 서버루트 설정
ServerRoot “c:/Apache24”

=> 변경할 필요 없음.

3-2. 포트 설정
Listen 80

=> 변경할 필요 없음.

3-3. 웹문서 저장위치 설정
DocumentRoot “c:/Apache24/htdocs”
<Directory “c:/Apache24/htdocs”>

=> 변경할 필요 없음. 만약 변경한다면 주소 2개를 동일하게 맞춰주자.

3-4. 서버네임 설정

#ServerName www.example.com:80

=> 찾아서 바로 아래에 다음과 같이 입력한다.
ServerName localhost:80 또는 ServerName 127.0.0.1:80

이 때, 포트(ex: 80)는 3-2와 똑같이 맞춰준다.

4. 환경변수 세팅
[제어판](Window키+R -> control 입력 후 엔터) -> [시스템 및 보안] -> [시스템] -> [고급 시스템 설정] -> [시스템 속성] 윈도우의 [고급] 탭 -> [환경 변수] -> 아래쪽 [시스템 변수] 목록에서 [Path] 항목을 찾아 [편집] 클릭 -> [새로 만들기] 로 C:\Apache24\bin 경로 추가 후 [확인] 클릭

5. 명령 프롬포트를 관리자 권한으로 실행한다.
httpd -k install 입력하고, 방화벽 해제 윈도우가 뜨면 [엑세스 허용] 클릭한다.

httpd -k start 입력한다.

6. 인터넷 브라우저에 http://localhost/ 입력한다.
It works! 라고 나오면 아파치 웹서버 띄우기 성공이다.

C++ 스태틱 메서드 만들기

C++ 스태틱 메서드 만들기

C++ 로 스태틱 메서드를 만들어본다. 우선 알아야할 것은 C++ 로 Hello World 작성이 가능해야 한다.

(참고 : C++ 로 Hello World 작성 https://blog.naver.com/bb_/221194863950)

1. Visual Studio 의 좌측 [솔루션 탐색기] – [소스 파일] 폴더 위에서 우클릭 – [클래스 마법사] 클릭한다.

 

2. [클래스 마법사] 창이 뜨면 [클래스 추가] 버튼 클릭 – 클래스 이름을 적당히 입력 –  [마침] 버튼 – [확인] 버튼을 차례로 클릭한다.

 

3. 생성된 cpp파일과 h파일(헤더 파일)의 기본 내용은 아래 그림과 같다.

3-1. cpp 파일의 기본 내용

#include “TextUtil.h”

TextUtil::TextUtil()
{
}

TextUtil::~TextUtil()
{
}

3-2. h파일의 기본 내용

#pragma once
class TextUtil
{
public:
    TextUtil();
    ~TextUtil();
};

4. 아래와 같이 스태틱 메서드를 추가하고, 메서드를 call할 수 있다.

4-1. h파일(헤더파일)에 “static void 메서드명(파라미터);” 를 입력

#pragma once
class TextUtil
{
public:
    TextUtil();
    ~TextUtil();
    static void print(int i);
};

4-2. cpp파일에 “리턴값 파일명::메서드명(파라미터) {내용;}” 을 입력

#include “TextUtil.h”

TextUtil::TextUtil()
{
}

TextUtil::~TextUtil()
{
}

void TextUtil::print(int i) {
    // do something
}

4-3. 메서드를 call하고 싶은 특정 cpp에서 파일명::메서드명(파라미터);” 를 입력

#include “TextUtil.h”

int main() {
    TextUtil::print(1);
    return 0;
}


 

<엑셀VBA 입문 2강> 매크로 함수 만들기

<엑셀VBA 입문 2강> 매크로 함수 만들기

<엑셀VBA 입문> 머리말 : https://blog.naver.com/bb_/221211057971 

<엑셀VBA 입문 1강> 함수 : https://blog.naver.com/bb_/221232701246

2강이다. 머리말과 1강은 읽어도 좋고, 읽지 않아도 좋다.

엑셀은 사무용 프로그램이다. 그런데 VBA라는 프로그래밍 언어를 내부에 내장하고 있다. 다시 말하자면 마음먹고 코딩하면 프로그램도 작성할 수 있게 되어있다.

프로그램은 별다른게 아니다. 그저 여러 개의 함수로 이루어져 있는 것이다. 함수는 입력값을 넣으면 결과값을 되돌려주는 것을 말한다. 우리의 목표는 이러한 함수를 여러개 작성하여 업무를 단시간에 효율적으로 끝내보는 것이다.

엑셀은 기본적으로 함수를 제공하고 있는데, 우리가 아는 sum, sumif, count, counta 등이 기본함수다. 그런데 추가적으로 사용자가 원하는 함수를 새로 만들어 사용할 수 있다. 함수를 만드는 방법은 크게 3가지가 있다.

함수 만드는 방법 3가지

(1) 단축키로 실행 (매크로)

(2) 버튼을 클릭해서 실행

(3) 수식 입력줄에서 실행

가장 이해하기 쉽다고 생각하는 방법이 1번이다. 아래 절차를 따라 1번 함수를 만들어보자.

1. 엑셀을 켜고 상단 메뉴의 [보기] – [매크로] – [매크로 기록]을 클릭한다.

2. [매크로 기록] 창이 뜨면 바로가기 키에 Ctrl + k 를 입력하고 [확인] 버튼을 누른다.

3. 곧바로, [매크로] – [기록 중지] 를 클릭한다. (참고로 매크로의 정석은 매크로 기록(녹화)를 시작하고 사용자가 엑셀을 조작, 그 내용을 기억시킨 후 기록을 중지시키는 것이다.)

4. Alt – F11 키를 눌러 VBA를 켠다. [Microsoft Visual Basic For Application] 이라는 윈도우가 뜰 것이다. 약자로 VBA라고 한다.

 

5. 좌측의 [모듈] 폴더를 열고 [Module1] 파일을 더블클릭하면 아래와 같은 화면이 나온다. 아래 화면과 같이 End Sub 라고 쓰여있는 라인 바로 위의 줄에 MsgBox (“Hello World”) 라고 입력한다.

6. VBA 창을  끄고 나와서(저정하지 않아도 된다) 엑셀 화면으로 돌아온다. 엑셀 화면에서 Ctrl + K 키를 누르면 Hello World라고 쓰여진 메시지 박스가 뜬다.

이렇게 간단하게 사용자 정의 함수를 만들어보았다. 보다시피 Ctrl + k 단축키를 누르면 함수가 실행된다. 검색을 통해 VBA 명령어를 보고 한줄씩 입력하는 식으로 실습하면 좋다.

이어지는 글 <엑셀VBA 입문 3강> 버튼 클릭하면 실행되는 함수 만들기 : https://blog.naver.com/bb_/221249068033

이어지는 글 <엑셀VBA 입문 4강> 수식 입력줄에서 함수 실행하기 : https://blog.naver.com/bb_/221249107922

이어지는 글 <엑셀VBA 입문 5강> 특정 단어를 포함하는지 확인하는 함수 : https://blog.naver.com/bb_/221249954442

<엑셀VBA 입문 1강> 함수

<엑셀VBA 입문 1강> 함수

엑셀 VBA 입문 1강이다.

책을 써야한다는 생각에 사로잡혀 있다보니 글을 쓸 수 없었다. 페이지 구성, 목차 따위를 고민하다가 시간만 흘렀다. 각설하고, 마음을 비우고 VBA를 알려주는데에만 집중해서 쓰겠다.

본 강의의 목적은 회사 업무에 도움이 되는 팁을 제공하는 것이다. 강의를 읽으며 <어떻게 하면 내가 맡은 업무/과제에 도움이 될까?> 생각해보기 바란다.

(참, 만약 VBA가 무엇인지 대충 알고 있고, 한두번이라도 써본적이 있다면, 시간절약을 위해 이 강의를 읽지 않아도 된다. VBA를 심도있게 다루는 강의가 아니다. 말 그대로 입문이다.)

1강. 함수

엑셀에는 함수라는게 있다. 익히 알다시피 if, sum, sumif, count, counta 등이다. 함수란 입력값을 넣으면 출력값을 되돌려주는 것을 뜻한다.

예를 들면 아래와 같은 데이터가 있다고 하자.

 

딱 보기에도 빈약해보이는 데이터지만, 몇백만건의 업무 데이터라고 상상하며 진행하자.

간단한 문제를 풀어보자. 서울에 있는 점포수는 총 몇개일까?

데이터가 적다면 직접 세는게 빠르지만, 많다면 엑셀 함수가 압도적으로 빠르다. 이 경우 sumif 함수로 간단히 해결할 수 있다.

=SUMIF(대상영역, 조건, 덧셈할영역) 으로 쓴다.

하지만 만약 데이터가 아래와 같은 모습이었면 어떨까? 곧바로 sumif를 사용하기는 어려울 것이다.

이때 자주 사용하는 함수가 left, mid, right와 같은 함수다. 첫번째 열의 앞쪽 2글자를 떼어 다른 열에 위치시켜둔다면(캐싱), 앞서와 동일하게 sumif로 문제를 해결할 수 있다.

A열의 주소의 앞쪽 2글자를 left함수로 떼어 C열에 캐싱해두었다. 이어서 F열에서 sumif를 사용하였다. 여기까지가 일반적인 엑셀 함수의 사용법이다. 이렇게 여러 함수를 잘 섞어쓰는 것만으로도 업무를 잘해낼 수 있다.

그런데 만약 이것보다 조금 더 개선된 함수를 필요로 하고 있는 상황이라면 어떨까?

예를 들어 부산, 대전이 아니라 광역시만 count하거나 sum하고 싶다면 어떨까? 지금과 같은 데이터에서는 mid함수를 이용해 3번째 글자부터 3글자씩을 가져와 처리해볼 수 있다. 아래 그림처럼 말이다.

하지만 운 좋게 특별시라는 단어가 모두 같은 위치(3번째 글자부터 3자리)였기에 망정이지, 찾고자 하는 단어가 랜덤한 자리에 위치한다면 left, mid, right 함수를 사용할 수 없다.

위치에 상관없이 특정 단어를 포함하는지 알고 싶을 때는 search 또는 find 함수를 쓴다. 예를 들어 =IF(ISERROR(SEARCH(찾을문자, 대상텍스트), -1, SEARCH(찾을문자, 대상텍스트)) 식으로 쓰면 찾는 문자가 대상 텍스트의 몇 번째에 위치하는지 알아낼 수 있다.

아래는 search(또는 find), if, countif 함수를 동원해 <사과>라는 단어가 몇 번 출현하는지 세어보았다.

결과적으로 사과의 개수를 5개로 세고 있다. 그러나 몇 가지 한계점이 드러난다.

우선 함수가 너무 길고 복잡하다. 또한 포함하는 것을 찾아내는 함수(search, find)로는 원하는 결과를 얻지 못할 수도 있다. 예를 들어 A2 칸의 <사과상자 속의 사과>라는 문구 속에서 <사과>라는 단어는 2번 출현한다. 하지만 search로는 포함되는지 포함되지 않는지를 알아낼 수 있을 뿐, 특정 단어가 몇 번 출현하는지까지 셀 수는 없다.

이제부터가 시작이다.

엑셀의 함수는 무수히 많지만, 그런 함수들이 조금 불편하다고 여겨졌다면, VBA를 배워 새로운 함수를 만들어낼 수 있다.

만약 여태까지 그런 생각을 하지 않았다면, 앞으로는 일부러 해보는 것도 좋을 것이다.

목적은 어디까지나 업무를 좀 더 스마트하게, 신속하게 끝내는 것이다. 거기다 VBA를 다들 못하는 곳에서 혼자 잘하면 유능하다는 인상을 확실히 심어줄 수 있다.

2강은 함수 만들기다.

이어지는 글 <엑셀VBA 입문 2강> 매크로 함수 만들기 : https://blog.naver.com/bb_/221234382213

이어지는 글 <엑셀VBA 입문 3강> 버튼 클릭하면 실행되는 함수 만들기 : https://blog.naver.com/bb_/221249068033
이어지는 글 <엑셀VBA 입문 4강> 수식 입력줄에서 함수 실행하기 : https://blog.naver.com/bb_/221249107922

윈도우 부팅USB 쉽게 만들기 (Rufus)

윈도우 부팅USB 쉽게 만들기 (Rufus)

Rufus는 윈도우 부팅 USB/리눅스(우분투) 부팅 USB를 쉽게 만들 수 있는 방법을 제공한다.

간단한 사용법

1. 빈 USB(포맷되어도 상관없는 USB)를 컴퓨터에 꽂는다.

2. 윈도우/리눅스 등 iso 파일을 다운받는다. (ex: Windows10.iso)

3. 상단의 [장치] 콤보박스를 USB가 꽂힌 드라이브로 지정한다. (ex: D드라이브)

4. 하단의 FreeDos라고 적혀진 콤보박스를 클릭하고 FreeDos ->ISO이미지로 변경, 바로 우측의 CD 아이콘을 클릭하여 iso를 지정한다.

5. 최하단의 [시작] 버튼을 누른다.

6. 부팅 USB 완성.

첨부된 rufus-2.18.zip 를 다운받아 사용하면 된다.

 

윈도우 CD키, 오피스 CD키 알아내는 방법 (KeyFinder)

윈도우 CD키, 오피스 CD키 알아내는 방법 (KeyFinder)

KeyFinder는 윈도우 CD키, 마이크로소프트 오피스 CD키를 알아낼 수 있는 프로그램이다. 본 소프트웨어는 Freeware이므로 안심하고 쓰시길. 첨부된 keyfinder.zip을 다운로드하면 된다.

 

윈도우 10 부팅USB 만들기, 이 도구를 실행하는 동안 문제가 발생했습니다. 오류해결

윈도우 10 부팅USB 만들기, 이 도구를 실행하는 동안 문제가 발생했습니다. 오류해결

윈도우 10 부팅 USB를 만들기 위해 MediaCreationTool.exe 를 실행했을 때, “윈도우 10 이 도구를 실행하는 동안 문제가 발생했습니다.” 라는 오류가 발생하는 경우가 있다. (아래 화면 참고)

이를 해결하기 위해서는 C:\Windows\SoftwareDistribution\Download 폴더 내부의 모든 파일을 삭제한 후, 윈도우 재시작하여 다시 MediaCreationTool.exe 파일을 실행하면 된다.

만약 Download 폴더 내부의 파일이 실행 중이라며 삭제되지 않는다면, 윈도우 재시작을 반복해 모든 파일을 다 지우고, 최종적으로 다시 재시작하여 부팅 USB를 구워보자.

MySQL Error Code: 1175 해결

MySQL Error Code: 1175 해결

MySQL Workbench 에서 업데이트 또는 딜리트 쿼리를 실행했을 때 아래와 같이 Error Code: 1175 가 발생하는 경우가 있다.

Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect.

이것은 SAFE MODE(안전모드)가 걸려있는 상태이므로 해제하는 명령어를 날리면 된다.

— 현재 SAFE MODE 값 확인

SELECT @@SQL_SAFE_UPDATES;

— SAFE MODE 설정

SET SQL_SAFE_UPDATES = 1;

— SAFE MODE 해제

SET SQL_SAFE_UPDATES = 0;

그런데 update 구문을 실행할 때마다 SAFE MODE를 해제한다는 것은 귀찮은 일이다. 따라서 SAFE MODE 기본값을 설정할 있는 메뉴가 제공된다.

MySQL Workbench 상단 메뉴의 Edit – Preferences – 좌측 리스트의 SQL Editor – Other 칸의 “Safe Updates”. Forbid UPDATEs and DELETEs with no key in WHERE clause or no LIMIT clause. Requires a recommection 을 체크해제한다.

다만 AutoCommit 기본값을 확인할 필요가 있다. 만약 AutoCommit이 설정되어 있는데 안전모드를 해제하면 데이터를 실수로 날려버릴 가능성이 매우 높아진다. 따라서 안전모드 해제전 AutoCommit을 우선 해제하기를 권장한다. (MySQL Workbench 오토커밋(AutoCommit) 해제하기 : https://blog.naver.com/bb_/221230947655)

MySQL Workbench 오토커밋(AutoCommit) 해제하기

MySQL Workbench 오토커밋(AutoCommit) 해제하기

MySQL Workbench로 MySQL DB에 접속했을 때 AutoCommit 설정이 기본값이다. 실수로 데이터를 날려버릴 가능성이 있기 때문에, AutoCommit을 해제하기를 권장한다. (필자는 MySQL Workbench 6.3 CE 버전 사용)

— 현재 AutoCommit 값 확인

SELECT @@AUTOCOMMIT;

— AutoCommit 설정

SET AUTOCOMMIT = 1;

— AutoCommit 해제

SET AUTOCOMMIT = 0;

그런데 MySQL Workbench를 기동할 때마다 SET AUTOCOMMIT = 0; 명령어 실행하는 것을 깜빡할 수 있다. 따라서 언제나 AutoCommit이 해제되어 시작되도록 설정할 수 있는 메뉴가 제공된다.

MySQL Workbench 상단 메뉴의 Edit – Preferences – 좌측 리스트의 SQL Editor 내의 SQL Execution – General 칸의 Leave autocommit mode enabled by default 를 체크해제한다.

MySQL Workbench를 껐다 켜서 다시 접속한 뒤 SELECT @@AUTOCOMMIT; 를 쿼리 날려서 0 값이 나오면 성공이다.

[Eclipse] 이클립스 실행시 인코딩 UTF-8 설정

[Eclipse] 이클립스 실행시 인코딩 UTF-8 설정
이클립스 UTF-8 설정하는 방법은 ini 파일을 고치면 된다. eclipse.exe 가 위치한 폴더내에 eclipse.ini 파일이 있다.

-vmargs 라고 적힌 라인을 찾고, 그 아래줄에 다음과 같이 입력하면 된다.

Dfile.encoding=UTF-8

스크린샷 참조할것.

(펌글)가짜 프로그래머 vs 진짜 프로그래머

(펌글)가짜 프로그래머 vs 진짜 프로그래머

가짜: 책상에 온통 책으로 덥혀있다. 자세히 보면 웹부터 시스템 프로그래밍까지 동내서점같다. 그런 자기 책상을 보며 자랑스러워 한다.

진짜: 책상에 담배재와 잡동사니만 굴러다닌다.

가짜: 모르는것이 있을때는 여기저기 관련 사이트에 Q&A에 질문을 올리고 답변을 기다린다.

진짜: 모르는것이 있을때는 Q&A를 뒤져보고 없으면 깡으로 만든다.

가짜: 짜본것보다 아는게 더 많타

진짜: 아는것보다 짜본게 더 많타

가짜: 직업을 물어보면 프로그래머라고 당당하게 말한다.

진짜: 직업을 물어보면 우물쭈물 하다가 상대에 따라 ‘컴퓨터 하는 사람’, ‘소프트웨어쪽 하는사람’ 자꾸 자세히 물어보면 ‘프로그램 짜는 사람’ 등 프로그래머라는 말을 피한다.

가짜: 부탁하면 머든지 한다. 물론 끝까지 한다는 보장은 없다.

진짜: 부탁하면 곤란한 표정을 짓는다. 어쩔수 없이 하게되면 수단과 방법을 안가리고 끝을 본다.

가짜: 컴퓨터 관련은 뭐든지 물어보면 모르는게 없다. 아주 성의있게 요목조목 설명해준다.

진짜: 물어보면 아는게 없다. 중요한 질문이나 확실히 아는것만 간단하게 말한다.

가짜: 다른사람이 잘 공부하지 않는 분야를 익히면 자신이 그분야 전문가가 된줄 안다. 그러나 기술을 재대로 써보지는 못한다.

진짜: 다른사람이 잘 공부하지 않는 분야는 쓸모가 없기 때문에 배우지 않는다. 반드시 필요하면 대강 배워서 쓰고 잊어버린다.

가짜: 시간만 나면 관련 게시판 TIP이나 강좌를 읽으면서 외공을 연마하여 자랑하고 다닌다.

진짜: 시간 나면 가끔식 자료구조,알고리즘,인공지능학, 영상처리학등 개론서를 훝어보면서 내공을 연마한다. 누가 물어보면 논다고 한다.

가짜: 클래스만 쓰면 OOP프로그램인줄 안다.

진짜: 마음만 먹으면 프로그램을 비지오로도 짤수도 있다.

가짜: 100만큼 배워서 10만큼 쓴다. (C/C++/API/MFC/VB바이블을 쓸수 있을정도로 알고 있어도 프로그램은 1000 줄이상 못짠다.)

진짜: 10만큼 배워서 1000만큼 쓴다.( if문만 배워도 만든다.)

가짜: 자신이 프로그래밍에 소질이 있다고 생각한다.

진짜: 자신은 프로그래밍에 소질이 없다고 생각한다. (입버릇처럼 때려치울꺼라고 하면서 부지런히 짠다.)

가짜: 코딩할때 타자속도가 600타 이상 나오며 부지런히 친다.

진짜: 한참 담배피다 300타 이하 속도로 몇자치고 또 담배핀다.

가짜: 마지막 10%가 고비다.

진짜: 처음 10%가 고비다.

가짜: 빌게이츠,리누스,잡스등 IT유명인들에 관심이 많고 때론 동경한다.

진짜: 아무 관심없다.

가짜: 언제나 최신 컴퓨터에 최고급 사양으로 유지하고 잡다한 부품이나 오버클럭등에 관심이 많타

진짜: 컴파일러가 뜨는데 지장 없으면 컴퓨터에는 관심 없다. 스피커에만 관심을 가진다.

가짜: 최적에 작업 환경을 요구한다. (조용하고, 남의 시선이 안닫고 구석진곳등등..)

진짜: 컴퓨터만 있으면 작업한다.

가짜: 알고 있는 모든 프로그램이 다 깔려있다. 깔면 다 사용할수 있다고 생각한다. ; 물론 나가서도 그렇게 말하고 다닌다. 윈도우 태마나 바탕화면등에 신경을 많이쓴다.

진짜: 아무 관심없다.

가짜: 심심하면 인터넷에서 특이한 테크닉 소스나 완성된 프로그램 소스를 구해서 구경하고 누가 물어보면 자신이 짰다고 말한다.

진짜: 필요하지 않타면 남의 소스에 관심 없다.

가짜: 가능한한 남이 못알아 보게 짠다. 물론 주석도 안단다.

진짜: 가능한한 남이 알아보기 쉽게 짠다. 주석은 가끔식 단다

가짜: Q&A게시판에서 조금이라도 들어본 질문이 올라오면 다 아는듯 답변을 단다.

진짜: 게시판을 잘 이용하지 않는다.

가짜: 온갓 유명 컴퓨터 서적과 잡지를 부지런히 사다 모은다.

진짜: 가끔식 잡지나 한번씩 사고, 절판되었거나 절판직전 책을 어렵게 구해다 본다.

가짜: 책의 목차와 앞에 몇패이지만 본다. 그러면 그 책을 다봤다고 생각한다..

진짜: 목차도 보지않는다. 가끔식 뒤에 색인만 살핀다.

가짜: 가짜들 끼리 모이면 잘 될줄 안다.

진짜: 진짜들 끼리 모이면 잘 안된다.(가짜가 좀 끼어있어야 한다.)

가짜: 가짜가 하는모습을 동경하고 따라할려고 한다.

진짜: 가짜처럼 살려고 노력한다.

진짜와 가짜가 만나서 프로그래밍 이야기를 하면…. 

가짜: 입으로 프로그램을 짠다. (현란한 첨단기술은 다써서)

진짜: 머리로 다짜고 컴파일 시켜서 컴파일된 결과만 말한다. ( if/for만 써서)

가짜: DirectX를 다 익히면 게임 만들수 있을줄 안다.

진짜: DirectX를 다 모른다. 그러나 필요하면 게임은 만든다.

———-

어떤 사이트에서 퍼온 글. 어떤 분은 열을 내던데, 난 나름 재미있게 읽었다.

나는 거의 모든 부분에서 가짜 프로그래머에 해당함. 에효…

출처 1 : http://www.masque.kr/index.php?&mid=free&document_srl=2066

출처 2 : https://kldp.org/node/71715

<엑셀VBA 입문> 머리말

<엑셀VBA 입문> 머리말

* 책을 쓰고자 합니다. 분량이 적은, 얇고 작은 책을 쓰고자 합니다. 주제는 엑셀VBA 입문 입니다.

프롤로그 : 느긋한 여가를 즐기고 싶다면 엑셀VBA를 배워라

오래 전부터 엑셀의 VBA 기능을 사용해왔다. 배워보면 어렵지 않고, 업무시간을 단축하는데에 큰 효과를 볼 수 있다. 게다가 할줄 아는 사람이 적다. VBA라는 단어 자체를 들어본 적 없는 동료들도 많다. 조금만 배워두면 주변으로부터 좋은 평가를 받을 수 있다.

대학생 때 언론사에서 아르바이트를 했다. ERP 프로그램에 수당을 입력하고 전표를 만들어내는 작업이었다. 어려운 일은 아니었으나 분량이 많아 시간이 오래 걸리는 작업이었다. 엑셀VBA를 이용해 자동화시켰다. 사람이 하면 3~4일 걸리는 일을 엑셀VBA가 2~3시간으로 단축시켰다.

어려운 수준까지 배울 필요도 없다. 간단한 수준으로 배워두면 써먹을 데가 많다. 생각해보면 어떤 분야의 일이든 심화 과정을 배우는 것이 어렵지, 입문 수준으로 무엇을 배운다면 특별히 어렵지 않다. 특히 엑셀은 어떤 분야에 종사하든 회사원의 필수 프로그램 중 하나다. 그만큼 엑셀VBA는 한 번 배워두면 오랫동안 써먹을 수 있다.

이 책의 대상 독자는 다음과 같다.

– 엑셀의 기본 함수(SUM, AVERAGE, IF 등)를 알지만 엑셀VBA는 모르는 사용자

– 엑셀을 잘해보고 싶은 회사원

– 기초 프로그래밍에 관심이 있는 사람

이어지는 글 <엑셀VBA 입문 1강> 함수 : https://blog.naver.com/bb_/221232701246

이어지는 글 <엑셀VBA 입문 2강> 매크로 함수 만들기 : https://blog.naver.com/bb_/221234382213

이어지는 글 <엑셀VBA 입문 3강> 버튼 클릭하면 실행되는 함수 만들기 : https://blog.naver.com/bb_/221249068033

공개질문 (엑셀/업무)

공개질문 (엑셀/업무)

안녕하세요. 여쭙고 싶은게 있어서 씁니다.

3가지인데요.

1. 회사에서 엑셀 많이 쓰시나요? 매일? 일주일에 한번? 한달에 한두번?

2. 엑셀을 쓰신다면 어떤 함수/어떤 기능/어떤 작업을 많이 하시나요? 궁금해요.

3. 엑셀에 이런 함수 없나, 이런 함수 있으면 참 좋겠다 싶었던 적 있나요? 있다면 설명해주세요.

다른건 아니고요. 제가 독자/이웃분들께 해드릴 수 있는건 없고…

간단한 강의라도 제공해볼까 싶어서요.

C++ 난수생성

C++ 난수생성

정수 fromNum 이상, 정수 toNum 이하의 난수를 리턴한다.

#include <cstdlib>
#include <ctime>

// 난수생성 (정수 fromNum 이상, 정수 toNum 이하의 난수를 리턴)
int NumberUtil::getRandomNumber(int fromNum, int toNum) {
    // 타임값으로 시드생성
    int seed = (unsigned int)time(NULL);
    srand(seed);

    // rand() % M + N ==> N 이상 (M+N-1) 이하 난수생성
    int n = fromNum;
    int m = toNum – fromNum + 1;
    int res = (rand() % m) + n;
    return res;

}

cocos2d-x 007 해상도 조절 (전체화면 모드와 윈도우 모드)

cocos2d-x 007 해상도 조절 (전체화면 모드와 윈도우 모드)

흑곰입니다. 느린 속도지만 c++로 게임 만들기에 도전하고 있습니다. cocos2d-x[코코스 투디 엑스]라는 엔진을 씁니다. 오늘은 해상도 조절하는 법을 배워봅니다.

개인적으로 제일 선호하는 방식은 윈도우 모드에, 창을 리사이즈하면 게임내 이미지 사이즈가 비례하여 조절되는 것인데요. cocos2d-x에서 쉽게 구현할 수는 없는 모양이고, 본 포스트에서는 생략합니다. 검색해보니 윈도우 리사이즈할 경우 특정 메서드를 call해서, 그에 맞게 그림을 다시 그려주는 방식으로 구현해야 하는 것 같습니다.

1. 기본값 (크기가 지정되지 않은 윈도우 모드)

cocos2d-x의 기본값은 윈도우 모드이며, AppDelegate.cpp 파일의 applicationDidFinishLaunching 메서드에 구현되어 있습니다.

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLViewImpl::create(“My Game”);
        director->setOpenGLView(glview);
    }

    // turn on display FPS
    director->setDisplayStats(true);

    … 중략 …

    return true;
}

2. 윈도우 모드(크기 지정)

코드를 아래와 같이 바꾸면 크기를 지정한 윈도우 모드가 됩니다.

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        // 윈도우 모드(사이즈 지정)
        glview = GLViewImpl::createWithRect(“My Game”, Rect(0, 0, 800, 600));
        director->setOpenGLView(glview);
    }

    // 윈도우 모드(사이즈 지정)
    glview->setDesignResolutionSize(800, 600, ResolutionPolicy::SHOW_ALL);

 
    // turn on display FPS
    director->setDisplayStats(true);

    … 중략 …

    return true;
}

3. 전체화면 모드

코드를 아래와 같이 바꾸면 전체화면 모드가 됩니다. 전체화면이라도 setDesignResolutionSize 메서드 인자에 해상도를 적어주어야 합니다. 그래야 특정 해상도에 맞게 전체화면 모드가 되니까요.

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        // 전체화면 모드
        glview = GLViewImpl::createWithFullScreen(“My Game”);
        director->setOpenGLView(glview);
    }

    // 전체화면 모드
    glview->setDesignResolutionSize(800, 600, ResolutionPolicy::SHOW_ALL);
 
    // turn on display FPS
    director->setDisplayStats(true);

    … 중략 …

    return true;
}

참고. ResolutionPolicy

참고로 ​ResolutionPolicy라는 단어가 계속 나오는데, 말 그대로 해상도 정책을 의미합니다. 해상도 정책은 5가지가 있으며 원하는 정책을 갖다 쓰면 됩니다.

아래 설명은 인자건 님의 <Cocos2d-x 3 모바일 게임 프로그래밍>에서 가져옴을 밝힙니다.

(관련링크 : https://blog.naver.com/injakaun/220030612962)

1. EXACT_FIT : 화면 비율을 고려하지 않고 무조건 입력한 게임 해상도에 맞춤

2. NO_BORDER : 화면 비율을 고려해 최대한 많이 보일수 있게 확대, 축소함 (화면이 짤려보임)

3. SHOW_ALL : 화면 비율을 고려해 모든 화면이 보일 수 있게 확대, 축소함 (검은색 여백이 생김)

4. FIXED_WIDTH : 화면의 너비는 게임 해상도로 고정하고 높이는 단말기 해상도에 따라 가변적임

5. FIXED_HEIGHT : 화면의 높이는 게임 해상도로 고정하고 너비는 단말기 해상도에 따라 가변적임

엑셀VBA 한영전환

엑셀VBA 한영전환

VBA 시작시 키입력의 상태가 항상 영문(또는 한글)이도록 세팅하고 싶을 때가 있다.

이를 위해 구글/네이버에서 각종 키워드를 동원해 검색할수록 굉장히 어렵고 난해한 내용을 찾을 수 있다.

IME가 어쩌고… 개인적으로 깊고 어려운 지식에는 약한 편이라, 가장 쉽고 단순무식한 방법을 제시한다.

결론은 엑셀 스프레드 시트에 알파벳 하나를 입력시키고, 그게 a일 경우 영어로 인식하고 ㅁ일 경우 한글로 인식하는 방법이다.

코드는 아래와 같다.

‘키보드 상태확인을 위한 선언하기
Private Declare Function GetAsyncKeyState Lib “user32” (ByVal vKey As Long) As Integer

‘키입력을 위한 선언하기
Const KEYEVENTF_EXTENDKEY = &H1
Const KEYEVENTF_KEYUP = &H2
Private Declare Sub keybd_event Lib “user32.dll” (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

‘시간지연(슬립)을 위한 선언하기
Public Declare Sub Sleep Lib “kernel32.dll” (ByVal dwMilliseconds As Long)

Sub Macro1()

‘ Macro1 Macro

‘ 바로 가기 키: Ctrl+k

‘ A를 입력하고 엔터를 누른다.
Sleep (1000)
Call typeA
Call typeEnter

‘해당 값을 기억후, 삭제한다.
Dim tmpVal
tmpVal = ActiveCell.Offset(-1, 0).Value

ActiveCell.Offset(-1, 0).Select
Call typeDelete

‘결과 표시
If tmpVal = “ㅁ” Then
    Call changeHangul
    MsgBox (“영문으로 전환되었습니다.”)
Else
    MsgBox (“이미 영문 상태입니다.”)
End If

End Sub

Function typeA()
‘에이
keybd_event 65, 0, 0, 0
keybd_event 65, 0, KEYEVENTF_KEYUP, 0
DoEvents
End Function

Function typeEnter()
‘엔터
keybd_event 13, 0, 0, 0
keybd_event 13, 0, KEYEVENTF_KEYUP, 0
DoEvents
End Function

Function typeDelete()
‘딜리트
keybd_event 46, 0, 0, 0
keybd_event 46, 0, KEYEVENTF_KEYUP, 0
DoEvents
End Function

Function changeHangul()
‘한영전환
Const VK_HANGUL = &H15
keybd_event VK_HANGUL, 0, KEYEVENTF_EXTENDEDKEY, 0
keybd_event VK_HANGUL, 0, KEYEVENTF_KEYUP, 0
DoEvents

End Function

엑셀VBA 클립보드 사용

엑셀VBA 클립보드 사용

아래와 같이 함수를 만들어쓸 수 있습니다.

1. 클립보드에 문자열 저장

Function setClip(str)

    Dim obj As Object
    Set obj = CreateObject(“new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}”)
    obj.setText str
    obj.PutInClipboard
    SetCB = True

End Function

2. 클립보드에서 문자열 꺼내기

Function getClip$()

    Dim obj As Object
    Set obj = CreateObject(“new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}”)
    obj.GetFromClipboard
    getClip = obj.GetText

End Function

이하 테스트 화면입니다.

Sub Macro1()

‘ Macro1 Macro

‘ 바로 가기 키: Ctrl+k

setClip (“클립보드에 저장할 내용”)

Dim result
result = getClip()

MsgBox (“출력 : ” + result)
End Sub

cocos2d-x 006 텍스트파일 읽기 / 한글 표시

cocos2d-x 006 텍스트파일 읽기 / 한글 표시

흑곰입니다.

cocos2d-x 에서 txt 파일 읽기, 그리고 화면에 문자열 띄우는 일이 만만치 않군요. 검색을 제법 많이 했습니다.

일단 화면에 영어와 숫자는 표시되는데 한글이 표시되지 않는 문제가 있었고요.

외부 파일로부터 한글을 읽어들이지 못하는 문제가 있었습니다.

마지막으로, 파일을 읽어들일 수 있는 폴더 경로를 알기 어려웠습니다.

그 과정에서 cocos2d-x 문자열 처리와 관련해 똥똥배님이 쓴 글을 발견했습니다.

무려 5년 전(!)의 포스팅인데요.

행여나 없어질까 싶어 스크린샷 파일로 박제해왔습니다.

(굳이 읽지 않고 skip하셔도 됩니다.)

감격의 눈물을 흘리며(?) 열심히 읽어보았습니다.

요약하자면,

1. cocos2d-x는 애초에 UTF-8 기반입니다. 메모장에서 파일 저장시 인코딩을 UTF-8 로 선택하고 저장하면 한글을 잘 읽습니다.

2. 한글 문자열은 무조건 외부 파일을 읽어들여서 사용할 것. 여러가지로 그게 속편합니다.

이런 내용입니다.

여기에 제가 검색한/알아낸 정보를 덧붙여보자면 다음과 같습니다.

3. 한글을 표시할 때 한글 지원하는 폰트를 사용할 것. 이를 위해 네이버에서 무료 제공하는 나눔고딕을 설치했습니다.

4. 파일을 읽어들일 때 cocos2d-x 에서 제공하는 FileUtils 클래스를 사용해야 합니다.

그럼 텍스트 파일을 읽어 한글 문자열을 화면에 띄우는 것까지 설명해보겠습니다.

작업전 준비사항으로 폰트와 txt 파일이 있습니다.

1. 폰트 준비 : 네이버 검색해서 나눔고딕을 설치하고, C:\cocos2d-x-3.4\projects\basicgame\Resources\fonts 에 폰트 파일들을 넣었습니다. (NanumGothic.ttf / NanumGothicBold.ttf / NanumGothicExtraBold.ttf / NanumGothicLight.ttf)

2. temp.txt 준비 : Resources 폴더 안에 temp.txt 라는걸 만들었습니다. 경로를 찾아내기 위한 파일로, 내용은 아무렇게나 적어두었습니다. (내용이 한 글자 이상 있어야 할겁니다)

3. 1.txt 준비 : Resources 폴더 안에 text 라는 폴더를 만들고, 그 안에 1.txt 를 만들어두었습니다. 내용은 한글과 영어를 적당히 섞어서 3줄 써넣었습니다.

일단 지난번 만들었던 MainScene.cpp 의 init 함수 하단에 txt 파일을 읽고, 글자를 띄우는 코드를 적었습니다.

// txt 파일 읽기
TextManager *textManager = new TextManager();

 
vector<string> vec = textManager->readFile2Vector(“text/1.txt”);
textManager->logVector(vec);

delete textManager;

 // 글자 띄우기
string firstLine = vec[0];
auto label = Label::createWithTTF(firstLine.c_str(), “fonts/NanumGothic.ttf”, 24);
label->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height – label->getContentSize().height));
this->addChild(label, 1);

보시다시피 TextManager 라는 클래스를 만들었는데요.

이걸로 Resources\text\1.txt 를 벡터 형태로 읽어들이고(readFile2Vector), 벡터 내용을 로그로 쓴뒤(logVector),

첫 번째 줄의 내용을 화면에 띄우고 있습니다.

결국 TextManager의 내용이 핵심이 되겠죠.

아직 cpp의 헤더 개념도 모르겠고, 포인터 등 뭐가뭔지 모르겠지만… 나름대로 열심히 만들어보았습니다.

참고로 인크루드한 헤더 및 사용중인 네임스페이스는 다음과 같습니다.

#include “cocos2d.h”
#include <fstream>
#include <vector>
USING_NS_CC; // using namespace cocos2d
using namespace std;

———-

vector<string> TextManager::readFile2Vector(string path) {

    // 파일을 읽어들일 절대경로 얻기

    // string dirPath = FileUtils::getInstance()->getWritablePath();
    string dirPath = FileUtils::getInstance()->fullPathForFilename(“temp.txt”);
    dirPath = dirPath.substr(0, dirPath.length() – 8);
    log(“dirPath : %s”, dirPath.c_str());

    string filePath = dirPath + “” + path;
    log(“filePath : %s”, filePath.c_str());

    // 리턴용 벡터 선언
    vector<string> *result = new vector<string>();

    ifstream ifs(filePath);

    if (!ifs.is_open()) {
        log(“file not found : %s”, filePath.c_str());
        return *result;
    }

    // UTF-8의 앞의 불필요한 3바이트 제거
    char head[3];
    ifs.read(head, 3);

    char buf[1000];
    while (!ifs.eof()) {
        // 한줄씩 읽어들이기 (1000자까지)
        ifs.getline(buf, 1000);
        result->push_back((string)buf);
    }

    return *result;

}

void TextManager::logVector(vector<string> inputVector) {
    int vectorSize = inputVector.size();

    string ss = “”;
    for (int i = 0; i < vectorSize; i++) {
    log(“%i : %s”, i, inputVector[i].c_str());
    }
}

———-

우선 readFile2Vector 함수는, temp.txt를 이용해 절대 경로를 얻어내고, 글자 뒤쪽 8자리(temp.txt가 8글자입니다)를 잘라내서 Resource 폴더 경로를 얻습니다.

다음으로 1.txt 파일을 한줄씩 읽어 vector에 차곡차곡 쌓고요.

다 읽은 후에는 logVector로 벡터 내용을 로그에 찍어줍니다.

프로그램을 실행하면 아래처럼 나와야 합니다.

null 과 undefined 의 차이

null 과 undefined 의 차이

어떤 분께서 null 과 undefined 의 차이를 물어보셔서, 제가 읽었던 책을 근거로 직접 답변을 달아보았습니다.

var a; 는 언디파인드, 정의되지 않은 상태입니다. var a = null; 은 null 이라는 초기값이 부여된 상태입니다.

“대부분 undefined와 null을 자주 혼동합니다. 이 둘을 잘 구분하지 못하는 이유는 null == undefined가 true이기 때문입니다. 그러나 undefined와 null의 사용법은 많이 다릅니다. 초기화되지 않은 변수는 초기 값으로 undefined를 갖습니다. 즉 변수가 실제 값으로 초기화되기를 기다린다는 의미입니다.” (니콜라스 자카스 / 읽기 좋은 자바스크립트 코딩 기법 / p41)

“다음은 null을 사용하면 안되는 경우입니다. 함수의 인자 값을 확인하기 위해 null로 비교해서는 안된다. 초기화되지 않은 변수를 null로 비교해서는 안된다.” (니콜라스 자카스 / 읽기 좋은 자바스크립트 코딩 기법 / 40p)

부연하자면 니콜라스 자카스는 undefined 사용을 권장하지 않습니다. 이유는 var a; 를 쓰든 쓰지 않든간에(아무 코드가 존재하지 않든간에) typeof a 가 undefined 이기 때문입니다. var a = null; 을 사용함으로써 변수에 값 할당 예정임을 명시적으로 표현할 필요가 있습니다. 즉, undefined라는 것은 (자바스크립트 한정) 2가지입니다. (1) var a; (2) var a;라는 코드조차 없음. 보통은 후자를 의미하겠지요.