-
[ABAP] #37 ABAP 신문법SAP/ABAP 2026. 2. 3. 09:50
명령형(Imperative) vs 선언형(Declarative) 프로그래밍
ABAP은 원래 Pascal이나 COBOL의 영향을 받아 명령을 순차적으로 내리는 명령형 언어로 시작했다.
하지만 최신 버전(7.40 이상)에서는 Java나 C++처럼 결과값을 바로 표현하는 선언형(표현식) 방식이 도입되었다.
- 명령형 (과거): ADD 1 to gv_counter. (카운터에 1을 더하라는 명령을 내림)
- 선언형 (현재): gv_counter = gv_counter + 1. (결과값이 무엇이어야 하는지 수식으로 표현함)
문자열 처리
1. 문자열 연결
" [Before]" CONCATENATE gv_var1 gv_var2 INTO gv_result. " [After] " gv_result = gv_var1 && gv_var2.2. String Template ( | | )
" 변수를 문자열 내부에 직접 삽입 ({ } 사용) " gv_string = |Hello { pa_name }|.- 포맷 옵션
" 시스템 날짜 포맷팅 (date = user 옵션) " gv_string = |{ sy-datum date = user }|. " 20260203 -> 2026.02.03로 출력 가능 " " 숫자/상수 포맷팅 (number = user 옵션) " CONSTANTS gc_pi TYPE p LENGTH 3 DECIMALS 3 VALUE '3.142'. gv_string = |{ gc_pi number = user }|.
문자열 함수
분류 함수명 용도 및 설명 검색 및 위치 find 특정 패턴이 처음 나타나는 위치(인덱스) 반환 find_end 특정 패턴이 끝나는 지점의 위치 반환 find_any_of 제시된 문자 중 어느 하나라도 처음 발견되는 위치 반환 find_any_not_of 제시된 문자에 포함되지 않는 첫 번째 문자의 위치 반환 contains 특정 문자열 포함 여부를 확인 (True/False 반환) matches 문자열이 정규식(Regex) 패턴과 일치하는지 확인 변형 및 수정 to_upper / to_lower 모든 문자를 대문자 또는 소문자로 일괄 변환 replace 특정 부분을 다른 문자열로 교체 (중첩 사용 가능) condense 불필요한 공백 제거 및 연속 공백을 하나로 축소 reverse 문자열의 앞뒤 순서를 완전히 뒤집음 translate 지정한 규칙에 따라 특정 문자들을 일괄 치환 repeat 문자열을 지정한 횟수만큼 반복해서 연결 추출 및 자르기 substring 시작 위치와 길이를 지정하여 부분 문자열 추출 substring_before / after 특정 문자(구분자)의 이전 또는 이후 문자열 추출 substring_from / to 특정 문자가 시작되는 곳부터 끝까지, 혹은 처음부터 특정 문자까지 추출 segment 구분자로 나뉜 문자열에서 n번째 조각(세그먼트)을 추출 shift_left / right 문자열을 왼쪽/오른쪽으로 밀어내고 남은 부분 추출 기타 특수 함수 distance 두 문자열 사이의 편집 거리(차이 정도)를 숫자로 계산 escape 특수 문자를 HTML 등에서 안전한 형식으로 변환 insert 특정 위치에 새로운 문자열을 삽입 concat_lines_of 인터널 테이블의 모든 행을 하나의 문자열로 결합 to_mixed / from_mixed 스네이크 케이스와 카멜 케이스 간의 명명 규칙 변환 문자열 함수 파라미터
인수(Argument) 의미 설명 case 대소문자 구분 대소문자를 구분할지 여부를 결정합니다. RESPECTING CASE 구문과 동일한 역할을 한다. occ 발생 횟수 (Occurrence) 찾고자 하는 문자열이 여러 번 나타날 때, 몇 번째 값을 처리할지 지정한다. off 시작 위치 (Offset) 문자열의 처음이 아닌, 특정 지점(오프셋)부터 처리를 시작하고 싶을 때 사용한다. len 길이 (Length) 처리를 수행할 문자열의 길이를 제한할 때 사용한다. regex 정규 표현식 단순 텍스트가 아닌 복잡한 패턴(Regular Expression)으로 찾기, 바꾸기, 매칭을 수행할 때 패턴을 입력한다. val 대상 문자열 (Value) 함수가 실제로 처리해야 할 원본 문자열 데이터 그 자체를 의미한다. sub 부분 문자열 (Substring) 찾거나 교체 대상이 되는 특정 부분 문자열을 지정한다. gv_string = 'ABAP uses lots of statements'. gv_string = replace( val = gv_string sub = 'STATMENTS' case = abap_false with = 'expressions' ). " 결과 : ABAP uses lots of expressions "
인라인 선언 (Inline Data Declarations)
변수를 프로그램 상단에서 미리 선언할 필요 없이, 값이 할당되는 시점에 DATA(...) 키워드로 즉석에서 선언하는 방식
1. 메서드 파라미터
cl_salv_table=>factory( IMPORTING r_salv_table = DATA(go_alv) CHANGING t_table = gt_data ).2. LOOP / READ TABLE
- 타입 자동 추론
LOOP AT gt_itab INTO DATA(gs_line). READ TABLE gt_itab INTO DATA(gs_line) INDEX 1.
Field Symbol 신문법
- MODIFY 불필요
LOOP AT gt_itab ASSIGNING FIELD-SYMBOL(<ls_line>). ENDLOOP. READ TABLE gt_itab ASSIGNING FIELD-SYMBOL(<line>).
SELECT 신문법
Case 1. 조회 결과에 맞춰 인터널 테이블이 자동으로 생성
SELECT * FROM sflight INTO TABLE @DATA(gt_sflight).Case 2. 선택한 필드들로만 구성된 새로운 구조의 인터널 테이블이 즉석에서 만들어짐
" 필요한 필드만 골라서 조회할 때 (쉼표 사용 주의!) " SELECT carrid, connid, fldate FROM sflight INTO TABLE @DATA(gt_flights).Case 3. 구조체(Work Area) 형태로 데이터를 가져올 때도 동일하게 사용 가능
SELECT SINGLE * FROM sflight INTO @DATA(gs_flight) WHERE carrid = 'LH'.
NEW 연산자 (객체 생성)
- NEW 뒤에 타입이 오는데 이때 #을 넣어줘도 됨.
- # : 좌변 타입을 보고 추론
- 중첩 생성 가능
go_custom = NEW #( container_name = 'CUSTOM100' ). go_alv = NEW #( i_parent = go_custom ). " 중첩 생성 " go_alv = NEW #( i_parent = NEW cl_gui_custom_container( container_name = 'CUSTOM100' ) ).
CAST / RTTI 신문법
- RTTI 코드 압축
" [Before] 구문법: 참조 변수들을 일일이 선언하고 ?= (연산자)로 캐스팅 " DATA: gt_ddic_fields TYPE ddfields, go_typedescr TYPE REF TO cl_abap_typedescr, go_structdescr TYPE REF TO cl_abap_structdescr. " 1단계: 이름으로 타입 기술 객체 획득 " go_typedescr = cl_abap_typedescr=>describe_by_name( 'SFLIGHT' ). " 2단계: 구조체 타입으로 다운캐스팅 (실제 타입 확인) " go_structdescr ?= go_typedescr. " 3단계: 필드 목록 획득 " gt_ddic_fields = go_structdescr->get_ddic_fields( ). " [After] 신문법: CAST 연산자로 한 줄에 처리 " DATA: gt_ddic_fields TYPE ddfields. gt_ddic_fields = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( 'SFLIGHT' ) )->get_ddic_fields( ).
IS INSTANCE OF / CASE TYPE OF
1. 단일 타입 체크 (IS INSTANCE OF)
" [Before] 구문법: RTTI 클래스를 사용하여 복잡하게 확인 " DATA: go_vehicle TYPE REF TO cl_vehicle, go_truck TYPE REF TO cl_truck, go_class TYPE REF TO cl_abap_classdescr. go_class ?= cl_abap_typedescr=>describe_by_object_ref( go_vehicle ). IF go_class->get_relative_name( ) = 'CL_TRUCK'. go_truck ?= go_vehicle. " 맞으면 다운캐스팅 실행 " ENDIF. " [After] 신문법: IS INSTANCE OF 연산자로 직관적인 확인 " IF go_vehicle IS INSTANCE OF cl_truck. go_truck ?= go_vehicle. ENDIF.2. 다중 타입 분기 (CASE TYPE OF)
- 다운캐스팅 + 분기 한 번에
CASE TYPE OF go_vehicle. WHEN TYPE cl_truck INTO DATA(go_truck). WHEN TYPE cl_bus INTO DATA(go_bus). WHEN OTHERS. ENDCASE.
VALUE # / REF # / CONV # / EXACT
1. VALUE # (데이터 생성)
" [Before] 구문법: Range 테이블과 구조체를 각각 선언하고 APPEND 해야 함 " DATA: gt_range TYPE RANGE OF sflight-carrid, gs_range LIKE LINE OF gt_range. gs_range-sign = 'I'. gs_range-option = 'BT'. gs_range-low = 'AA'. gs_range-high = 'DL'. APPEND gs_range TO gt_range. class=>method( it_range = gt_range ). " [After] 신문법: 메서드 호출과 동시에 Range 데이터 구성 및 전달 " class=>method( it_range = VALUE #( ( sign = 'I' option = 'BT' low = 'AA' high = 'DL' ) ) ).2. REF
- 참조 변수 즉시 생성
DATA: BEGIN OF gs_data, carrid TYPE s_carr_id, connid TYPE s_conn_id, fldate TYPE s_date, carrname TYPE s_carrname, END OF gs_data. DATA: ref_all TYPE REF TO data. gs_data = VALUE #( carrid = 'AA' connid = '17' fldate = '20250101' ). * 메모리 주소만 넘겨주기 (REF) GET REFERENCE OF gs_data INTO ref_all. " 구문법 " ref_all = REF #( gs_data ). " 신문법 " " 이 때, ref_all 안에 들어간 주소의 값이 궁금하다면? " WRITE: ref_all->*. "역참조 " "추가) 필드심볼 사용할 수도 있음 " FIELD-SYMBOLS: <fs>. "ref_all 메모리 주소를 동일하게 가리키게 됨 " ASSIGN ref_all->* TO <fs>. WRITE: <fs>.3. CONV
- 데이터 타입 변환: 기본타입, 구조체, 참조변수으로 가능
- 변환 시 자릿수가 맞지 않으면 데이터 소실이 일어날 수 있다.
(예: N타입에 'ABCD'가 넣으려고 하는 경우 '0000' 값이 들어간다.) - 유연한 처리
" [Before] 구문법: 파라미터 타입(STRING)에 맞게 임시 변수를 선언하고 복사해야 함 " DATA: gv_data TYPE c LENGTH 12 VALUE 'Hello ABAP', gv_string TYPE string. " 타입을 맞추기 위해 값을 옮겨 담는 과정이 필요함 " gv_string = gv_data. lcl_class=>do_something( CHANGING cv_data = gv_string ). " [After] 신문법: CONV # 연산자로 호출 시점에 즉시 형변환 및 전달 " DATA: gv_data TYPE c LENGTH 12 VALUE 'Hello ABAP'. lcl_class=>do_something( CHANGING cv_data = CONV #( gv_data ) ).4. EXACT # (무손실 보장)
- 할당 과정에서 데이터의 소실이나 잘못된 변환이 없는지 런타임에 체크하는 연산자
- 데이터가 잘못됐을 경우 덤프를 발생시킨다.
- 엄격한 처리
" [Before] 일반 할당: 타겟 변수의 길이를 넘어가면 조용히 잘림 " DATA: gv_connid TYPE s_conn_id. " 4자리 필드라고 가정 " gv_connid = 'ABCD123'. " 에러 없이 'ABCD'만 들어감 (데이터 손실) " WRITE gv_connid. " [After] 신문법: EXACT 연산자로 데이터 무손실 검사 " DATA: gv_connid TYPE s_conn_id. TRY. " 데이터가 잘릴 위험이 있으면 할당하지 않고 예외를 발생시킴 " gv_connid = EXACT #( 'ABCD123' ). WRITE gv_connid. CATCH cx_sy_conversion_data_loss. " 데이터가 잘리는 경우 실행될 예러 처리 로직 " WRITE 'Error: Data is too long and will be lost!'. ENDTRY.※ 덤프 발생
CX_SY_CONVERSION_NO_NUMBER : 숫자가 아닌 문자를 숫자 변수에 집어넣으려고 할 때 발생하는 런타임 에러.

CORRESPONDING
- 데이터 매핑(필드명 기준)
- MOVE-CORRESPONDING 대체
" [Before] 구문법 " DATA ls_target TYPE zstruct_type. MOVE-CORRESPONDING ls_source TO ls_target. " [After] 신문법: 인라인 선언으로 바로 생성 및 복사 " DATA(ls_target) = CORRESPONDING zstruct_type( ls_source ).예제 코드

* CORRESPONDING 구문 DATA: BEGIN OF gs_data, carrid TYPE s_carr_id, connid TYPE s_conn_id, fldate TYPE s_date, carrname TYPE s_carrname, END OF gs_data. DATA: gs_carrier TYPE scarr, gs_flight TYPE sflight. gs_carrier = VALUE #( carrid = 'AA' carrname = 'Airline' ). gs_flight = VALUE #( carrid = 'AA' connid = '0017' fldate = '20250101' ). gs_data = CORRESPONDING #( gs_carrier ). WRITE: gs_data-carrid, gs_data-connid, gs_data-fldate, gs_data-carrname. gs_data = CORRESPONDING #( gs_flight ). WRITE:/ gs_data-carrid, gs_data-connid, gs_data-fldate, gs_data-carrname.
BASE 키워드
- “기존 값을 기반으로 새 값을 만든다”는 뜻
- 기존 구조 / 내부 테이블 값을 복사
- 그 위에 일부 필드만 덮어쓰기
- 원본은 절대 변경 안 됨

* CORRESPONDING 구문 DATA: BEGIN OF gs_data, carrid TYPE s_carr_id, connid TYPE s_conn_id, fldate TYPE s_date, carrname TYPE s_carrname, END OF gs_data. DATA: gs_carrier TYPE scarr, gs_flight TYPE sflight. gs_carrier = VALUE #( carrid = 'AA' carrname = 'Airline' ). gs_flight = VALUE #( carrid = 'LH' connid = '0532' fldate = '20250101' ). gs_data = CORRESPONDING #( gs_carrier ). WRITE: gs_data-carrid, gs_data-connid, gs_data-fldate, gs_data-carrname. gs_data = CORRESPONDING #( BASE ( gs_data ) gs_flight ). WRITE:/ gs_data-carrid, gs_data-connid, gs_data-fldate, gs_data-carrname.
COND / SWITCH (표현식 분기)
- WHEN 조건문이 참이면 THEN 구문 실행, 거짓이면 ELSE 구문 실행
" COND (=IF문), SWITCH (=CASE문) " DATA: BEGIN OF ls_list, id(20) TYPE c, name(20) TYPE c, END OF ls_list. DATA: lt_list LIKE TABLE OF ls_list. DATA: lv_score TYPE i VALUE 88, lv_vip TYPE c VALUE 'X'. "점수에 따라 등급을 결정해서 변수에 할당 " DATA(lv_grade) = COND string( WHEN lv_score >= 90 THEN 'A' WHEN lv_score >= 80 THEN 'B' ELSE 'C' ). lt_list = VALUE #( BASE lt_list "기존 데이터 (있다면) 유지 " ( id = '001' name = 'BASIC' ) * ( COND #( WHEN lv_vip = 'X' * THEN VALUE #( id = '101' name = 'VIP' ) * ELSE VALUE #( id = '002' name = 'BASIC' ) * ) * ) ( SWITCH #( lv_vip WHEN 'X' THEN VALUE #( id = '101' name = 'VIP' ) ELSE VALUE #( id = '002' name = 'BASIC' ) ) ) ). cl_demo_output=>display( lt_list ).'SAP > ABAP' 카테고리의 다른 글
[ABAP] #38 교육 시스템 프로그램 실습 (1) 2026.03.04 [ABAP] #36 Tree (0) 2026.02.02 [ABAP] #35 Field Symbols + Excel Upload (1) 2026.01.31 [ABAP] #34 ABAP OOP - Class (2) (0) 2026.01.25 [ABAP] #33 ABAP OOP - Class (1) (0) 2026.01.16