자유 그리고 경험

[Google spreadsheet]자동화하기_윗줄 식 아랫줄에 복사_3편 본문

기술

[Google spreadsheet]자동화하기_윗줄 식 아랫줄에 복사_3편

배아줄기세포 2021. 11. 15. 00:22
반응형

연속 연재중인 예제와 함께하는 구글스프레드시트 매크로 만들기 3편입니다.

 

1편

 

[Google spreadsheet]자동화하기_윗줄 식 아랫줄에 복사_1편

엑셀을 쓰다가, 입력해 놓은 자료를 실시간으로 보면서 편집할 일이 많아지면서 구글스프레드 시트로 자연스럽게 넘어가게 되었습니다. 물론 요즘은 엑셀도 온라인 뷰어를 제공하지만, 결정적

valentine92.tistory.com

2편

 

[Google spreadsheet]자동화하기_윗줄 식 아랫줄에 복사_2편

지난번, 많은 분들께서 관심과 사랑을 주셨..다면 좋았을 것 같은 글 [Google spreadsheet]자동화하기_윗줄 식 고대로 복사_1편 엑셀을 쓰다가, 입력해 놓은 자료를 실시간으로 보면서 편집할 일이 많

valentine92.tistory.com

 

이번 포스팅에서는 2편에서 매크로로 기록한 코드를 살펴보고, 필요한 만큼 수정해서 좀 더 세련되게 다듬어보려고 했습니다만... 쓰다보니 너무 길어져서 코드만 살펴보도록 하겠습니다.

 

저번에 만들었던 파일에서 [확장프로그램]-[Apps Script]를 클릭하여 스크립트로 들어가봅시다.

스프레드시트 스크립트 보기
Apps Script가 스프레드시트 앱의 스크립트입니다.

쏼라쏼라~ 그래도 3번째 보니까 좀 거부감이 줄어드셨으려나요?

 

Google SpreadSheet Apps Script
이제는 조금 친해졌을지도?

코드는 다음과 같습니다.

/** @OnlyCurrentDoc */

function myFunction() {
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getActiveSheet();
  sheet.getRange(spreadsheet.getCurrentCell().getRow(), 1, 1, sheet.getMaxColumns()).activate();
  spreadsheet.getActiveSheet().insertRowsAfter(spreadsheet.getActiveRange().getLastRow(), 1);
  spreadsheet.getActiveRange().offset(spreadsheet.getActiveRange().getNumRows(), 0, 1, spreadsheet.getActiveRange().getNumColumns()).activate();
  spreadsheet.getCurrentCell().activate();
  spreadsheet.getCurrentCell().offset(-1, 0, 1, 3).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
};

영어가 조금 되신다면 코드해석은 쉬운 편입니다.

요즘은 '읽기 좋은 코드가 좋은코드다' 라는 인식이 개발자들 사이에서 퍼져있어서, 함수 이름 자체를 잘 알아들을 수 있게 짜놓는 추세거든요.


코드해석

윗줄부터 차근차근 해석해 보겠습니다.

/** @OnlyCurrentDoc */

JSDoc 문법으로, javascript에서 Documentation(문서화)에 도움을 주는 기술이라고 합니다. Java에서도 Notation이라는 비슷한 기술을 쓴 적이 있었는데,  javascript기반으로 만들어진 구글의 app script에서도 이것을 차용해 사용하고 있는 것 같습니다.

 

JSDoc 공식페이지(?)

 

Use JSDoc: Index

Index Getting Started Getting Started with JSDoc 3 A quick-start to documenting JavaScript with JSDoc. Using namepaths with JSDoc 3 A guide to using namepaths with JSDoc 3. Command-line arguments to JSDoc About command-line arguments to JSDoc. Configuring

jsdoc.app

다른 코드들을 보면 이것을 이용해서 사용자가 정의한 함수에 대한 설명, 각 파라미터에 대한 설명도 스프레드시트 상에서 뜰 수 있게 하더라구요.

 

이번 노테이션은 말 뜻 그대로, '이 함수는 현재의(current) 스프레드시트(Doc)에서만 사용하겠다' 라는 뜻입니다. 가끔 다른 파일에서도 코드(스크립트)를 공유하는 경우가 있어서 이를 방지하기 위해 자동으로 들어가는 것 같습니다.

 

이제부터 나올 코드관련 설명은 구글의 공식 App script 설명 페이지를 참고한 것입니다.

 

검색으로는 찾기 힘든 앱스크립트 설명페이지.

 

Spreadsheet Service  |  Apps Script  |  Google Developers

Send feedback Spreadsheet Service Spreadsheet This service allows scripts to create, access, and modify Google Sheets files. See also the guide to storing data in spreadsheets. Sometimes, spreadsheet operations are bundled together to improve performance,

developers.google.com

 

function myFunction() {

2편에서도 언급했던, 함수의 시작을 알리는 라인입니다.  'function'(영어로 함수라는 뜻) 은 함수가 시작되는 것을 알려주는 keyword(문법) 뒤에오는 'myFunction'은 이 함수의 이름입니다.  우리가 지어주는 이름이므로, 'MacroYes' 등과 같이 맘대로 지어도 됩니다.  함수의 상징인  괄호 기호 ' ( ) '도 써주고, 블록을 열어줍니다 '{'

 

var spreadsheet = SpreadsheetApp.getActive();

spreadsheet라는 변수를 선언해줍니다. var 는 'variable'(변수)의 약자로 이것도 keyword입니다. spreadsheet변수의 이름(변수명)  여기에 SpreadsheetApp.getActive()를 넣어주는데, 문서를 참고하지 않아도, 스프레드시트 어플중에, 지금 활성화(Active) 되어 있는 것을 변수에 넣겠다(=) 는 뜻같아 보입니다.  getActive라고 동사형을 쓰는 이유는,  getActive() 가 함수이기 때문일 것입니다. (괄호가 붙은 것을 보고 알 수 있습니다.)

'메소드는 동사형으로 짓는 것이 좋다' 는 조언에 충실한 함수(메소드)이름입니다.

여기서 선언하지 않고 쓰이는 변수, 함수들은 모두 구글스프레드시트에 내장(built-in)되어 있는 것들이라는 것. 알고 계시죠?

Spreadsheet.getActive() reference
getActive() 설명

var sheet = spreadsheet.getActiveSheet();

다음은 sheet 가 무엇인지 변수로 정하려고 하는 것 같습니다. 바로 앞에서 선언한 spreadsheet 변수를 활용하고 있습니다. 굉장히 똑똑한 자동 코딩 생성기네요! 

구글 스프레드시트 getActiveSheet() Reference
getActiveSheet() 설명

spreadsheet와 sheet의 차이는 무엇일까요?  spreadsheet는 파일자체 (엑셀로 치면 워크북. 또는 파일),  sheet는 그 파일에의 여러 시트중에 하나. 지금 선택되어 있는 시트입니다.  구글 스프레드시트의 앱 이름이 'spreadsheet'라 조금 혼돈을 주네요.

sheet.getRange(spreadsheet.getCurrentCell().getRow(), 1, 1, sheet.getMaxColumns()).activate();

sheet 변수를 다시 한 번 활용합니다. 긴 코드에 쫄지 말아야 합니다. 긴 함수가 큰 묶음으로는 어떻게 생겼는지 먼저 살펴보세요, 책을 보기 전에 차례 먼저 보는 것처럼요.

sheet.getRange().activate();

애초에 이런 형태 안에, getRange()의 파라미터로 네 개의 수가 들어간 것을 알 수 있습니다.

getRange()의 여러 형태들

getRange()는 여러가지 형태가 있는데, 그중에 Signature(파라미터의 수, 타입)가 같은 것은 세번째입니다. 처음에 가장 왼쪽 위 셀의 좌표를 알려주고, 그 뒤에 몇 개의 행, 몇개의 열을 이루는 범위인지 입력해서 그 범위를 구하는 함수입니다.

 

안쪽의 코드를 보니, 지금 선택한 셀 ( getCurrentCell() ) 의 행을 구하고 (get Row() )  거기서부터 시작해서 시트의 마지막 열( getMaxColumns() )까지 선택하려고 합니다. 즉, 선택한 셀이 속한 행을 모두 선택한다는 뜻이죠.

구글 스프레드시트 getCurrentCell()
getCurrentCell() 레퍼런스

그렇게 범위를 구하고 .activate() 로 활성화 해줍니다.

구글 스프레드시트 activate()
activate() 설명

매크로 녹화를 하기 전에 선택했던 셀이 속한 줄을 선택하는 코드였습니다.

 

CurrentCell과 ActiveRange의 차이에 대해서는 다음 글과 코드에서 알기 쉽게 설명이 되어 있는데, 이것까지 하나하나 설명하면 글이 너무 길어지므로, 생략하고 다음 포스팅 소재로 내 마음속에 저장📷~ 꼬리에 꼬리를 무는 포스팅, 꼬꼬포

구글 스프레드시트 셀렉션
엑셀에서도 구분이 헷갈렸던 Current와 Active

다음줄 보겠습니다.

spreadsheet.getActiveSheet().insertRowsAfter(spreadsheet.getActiveRange().getLastRow(), 1);

이제 함수가 중복돼서 보이기 시작하네요. 자주 쓰는 함수는 정해져있고, 그래서 반복됩니다. 이런 함수만 익숙해져도 코딩을 빠르게 잘할 수 있습니다. 활성화된 시트(getActiveSheet()) 에서 행을 삽입합니다. (어딘가의 뒤에서) (insertRowsAfter())

구글 스프레드시트 insertRowsAfter()
insertRowsAfter() 설명

insertRowsAfter() 에서 첫번째 파라미터는 삽입할 위치  = 선택한 범위(getActiveRange()의 마지막 줄(getLastRow()) 이고, 두번째 파라미터는 몇줄을 삽입할지 입력하면 되네요 (1)

이 때 getActiveRange() 에 가져오는 ActiveRange는 바로 윗줄에서 .activate()로 활성화 시켜준 범위입니다.

저희가 행을 삽입했던 동작을 기록한 코드였습니다.


여러분 조금 지치셨나요??? 저는 지쳤습니다..

하지만 아직 행 삽입까지 밖에 안했습니다. 복사 붙여넣기까지는 마저 해야죠!

 

spreadsheet.getActiveRange().offset(spreadsheet.getActiveRange().getNumRows(), 0, 1, spreadsheet.getActiveRange().getNumColumns()).activate();

마지막  .activate()를 보니 뭔가 또 활성화하는 코드입니다.

offset() 함수가 등장했습니다. offset 역시 여러 시그니쳐를 가지고 있습니다.

구글 스프레드시트 offset 레퍼런스
여러가지 offset 시그니쳐

위 코드의 쉼표의 갯수를 보아하니 맨 마지막 함수인 것 같습니다. 현재범위(current range)와 연관있는 범위 중  행.열이 앞의 두 파라미터만큼 이동한 셀에서부터 뒷쪽 두 파라미터(행, 열) 만큼 크기를 갖는 범위입니다.

음.. 조금 복잡하게 코드가 짜여진 것 같은데, 현재범위는 처음에 선택했던 셀이 포함된 행 전체인데, 그 행의 수만큼(getNumRows()) 아래로 내려갑니다. 즉, 한 칸 아래로 내려갑니다. 오른쪽으로는 0칸.

행은 1칸,  열은 현재범위의 열 갯수 (getNumColumns() ,즉 스프레드 시트 끝까지) 까지 범위를 선택합니다.

종합해보면, 새로 삽입한 행 선택이네요. 행 삽입을 하면 기본으로 선택되는 것 같기도 합니다.

 

spreadsheet.getCurrentCell().activate();

무슨 이런 의미없는 코드가.. (자동 코딩의 한계인가)

하지만 activeRange와 getCurrentCell을 구분해서 볼 줄 안다면,  Current Range 에서 가장 왼쪽 윗 셀만 current cell 로 취급하기 때문에, 행전체에서 가장 앞에있는 셀만 다시 선택해준 코드라는 의미를 부여할 수 있습니다.

 

spreadsheet.getCurrentCell().offset(-1, 0, 1, 3).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);

대망의 마지막줄입니다.

바로 윗줄에서 지정해 준 CurrentCell(삽입한 행의 맨 앞 셀) 에서 offset을 한번 더 해줍니다. 맨 앞부분이 -1 인 것을 보니 바로 윗줄의 데이터를 선택하려고 하고 있습니다. 옆으로 세칸까지 선택 했네요.

.copyTo()  드디어 복사가 나왔습니다. To 가 붙은 걸 보니,  앞의 범위를 어딘가로(to) 붙여넣기 하는 함수 같습니다.

구글 스프레드시트 copyTo 의 여러 시그니쳐
여러가지 copyTo 시그니쳐

이번에도 여러가지네요,  파라미터 세개는 두번째입니다. 좀 더 자세히 보겠습니다.

구글 스프레드시트 copyTo()
copyTo(변수 세개) 상세

읽어보니 쓸데 없이 세개짜리 쓴 것 같기도 합니다. 첫번째 변수가 가장 중요한 붙여넣기할 범위입니다. 깔끔하게 getActiveRange()로 currentRange를 선택해줬네요.

결국, 바로 윗값을 복사해서 아래에 붙여넣는 코드였습니다.

copyPasteType은 엑셀에서도 흔했던, 복붙을 하는 모드입니다. 모드는 더 깊게 들어가면 아래와 같이 설명이 나와있습니다. 코드에서 쓴 모드는 '모든 것을 복붙하는 모드' 라고 보시면 되겠어요.

google spreadsheet copypastetype
구글 스프레드시트 CopyPasteType

transposed는 복붙할때 '전치' (가로 세로 축을 바꾸는 것) 를 할지 말지인데, 당연히 안바꾸므로 false입니다. 데이터 전문가가 아닌 우리는 잘 안 쓰기 때문에 쓸 데 없는데 알아만 놓고 넘어갑시다~


이렇게 해서 

선택한 셀 바로 아래에 행 추가하고, 값 붙여넣기를 하는 동작을,  구글스프레드시트가 어떻게 기록했는지 코드를 하나하나 파보았습니다. 포스팅하면서 천천히 보니까 자동으로 기록하는 코드가 꽤 군더더기 없이 깔끔한 것 같네요.

 

초보자가 볼 것을 고려하여 하나하나 상세하게 쓰다보니 조금 길어졌습니다. 

중간중간에 코딩 관련 팁도 있으니 참고하면서 읽어보면 도움이 되실 것 같습니다.

 

4편에서 진짜 코드를 수정해보겠습니다~ 여기까지 따라오느라 고생많으셨습니다.

반응형
Comments