Common Lisp 문자열 관련 함수 사용법을 정리해보았습니다



문자열 자르기 & 치환

; 문자열 자르기
(subseq "abcdef" 2)
-> "cdef"

(subseq "abcdef" 0 2)
-> "ab"

; 문자열 치환
(defparameter str (string "abcdef"))
(setf (subseq str 0 2) "AB")
str
-> "ABcdef"

; 치환시 변경 전의 길이보다 변경 후의 부분이 더 길 경우, 변경 전의 길이만큼만 바뀐다. (늘어나지 않음)
(defparameter str (string "abcdef"))
(setf (subseq str 0 2) "ABC")
str
-> "ABcdef"

(setf (subseq "abcdef" 0 2) "AB") ; (X) 변수에 대해서만 사용가능하다

(setq (subseq str 0 2) "ABC") ; (X) setq가 아닌 setf만 가능함에 유의



문자열 결함

; 문자열 결합
(concatenate 'string "abc" "def") ; 문자열로 결합
-> "abcdef"

(concatenate 'list "abc" "def") ; 문자의 리스트로 결합
-> (#\a #\b #\c #\d #\e #\f)

; 문자열 포매팅
(format nil "this is ~A" '(a b c))
-> "this is (A B C)"


(format nil "this is ~{ ~A~}" '("abc" "def" "ghi"))
-> "this is  abc def ghi"



개별 문자 처리

; 개별 문자 얻기
(char "abcdef" 2)
-> #\c

; 개별 문자 치환
(defparameter str (string "abcdef"))
(setf (char str 5) #\g)
str
-> "abcdeg"

; 문자 -> 코드 변환
(char-code #\a)
-> 97

; 코드 -> 문자 변환
(code-char 97)
-> #\a



개별 문자 나열

; 한번에 한 문자씩 처리 : 익명 함수를 통해 직접 처리하는 방법
(map 'string #'(lambda (c) (print c)) "abcde")
-> #\a
#\b
#\c
#\d
#\e
"abcde"
 
; 한번에 한 문자씩 처리 : loop를 사용하여 문자 리스트를 얻어 처리하는 방법
(loop for char across "abcde" collect char)
-> (#\a #\b #\c #\d #\e)



문자 제거

; 특정 문자 제거
(remove #\b "abcdef")
-> "acdef"


(remove #\b "bbbbbb1" :start 2) ; 인덱스 2 이후 문자를 대상으로
-> "bb1"



; 특정 조건을 만족하는 문자 제거
(remove-if #'upper-case-p "AbCdEf") ; 대문자 제거
-> "bdf"

; 특정 문자 대체 (뒤엣것으로 앞엣것을 대체)
(substitute #\z #\a "abcdefga")
-> "zbcdefgz"

; 특정 조건을 만족하는 문자 대체
(substitute #\Z #'upper-case-p "AbCdEf")
-> "ZbZdZf"

; 특정 구간만큼 대체
(replace "abcdef" "12345" :end1 3) ; 인덱스 3 앞의 문자를 대상으로
-> "123def"



문자열, 문자 사이의 변환

; 길이가 1인 문자열 -> 문자
(coerce "a" 'character)
-> #\a

(coerce "ab" 'character) ; 길이가 1이 아닐 때 쓰면 에러 발생!

; 길이가 1이 넘는 문자열 -> 문자 리스트
(coerce "abc" 'list)
-> (#\a #\b #\c)

; 길이가 1인 문자열 <- 문자
(string #\a)
-> "a"

; 길이가 1이 넘는 문자열 <- 문자
(coerce '(#\a #\b #\c) 'string) ; 리스트로부터 생성
-> "abc"


(coerce #(#\a #\b #\c) 'string) ; array로부터 생성 (1)
-> "abc"


(defparameter some-array (make-array 4 :initial-element #\a)) ; array로부터 생성 (2)
(coerce some-array 'string)
-> "aaaa"



; [참고] array 정의 방법
(defparameter some-array (make-array 4 :initial-element #\a)) ; 길이가 4이고 a로 초기화



기타 처리

; 문자열 뒤집기
(reverse (string "abcde"))
-> "edcba"

; 대소문자 변환
(string-upcase "abcde")
-> "ABCDE"
(string-downcase "ABCDE")
-> "abcde"
(string-capitalize "abcde")
-> "Abcde"

; 문자열 트림 : 첫번째 파라미터의 문자들을 두번째 파라미터 끝에서부터 제거한다
(string-trim " " " abc def ")
-> "abc def"
(string-trim " ac" " abc abc ")
-> "bc ab"
(string-left-trim " ac" " abc abc ") ; 왼쪽에서부터 제거
-> "bc abc "
(string-right-trim " ac" " abc abc ") ; 오른쪽에서부터 제거
-> " abc ab
(string-right-trim '(#\Space #\a #\c) " abc abc ") ; 첫번째 파라미터로 문자열 대신 리스트 사용
-> " abc ab"



심볼 관련

; 문자열 -> 심볼(변수명 등) 변환
; - 단지 변환하는 것이 아닌 해당 심볼이 패키지에 존재하지 않을 경우 추가된다.
(intern "SOME-SYMBOL")

; 심볼 -> 문자열 변환
; - 심볼 존재 유무에 상관없이 동작
(symbol-name 'SOME-SYMBOL)
-> "SOME-SYMBOL"



문자 검색

; 문자 검색 후 발견한 문자 반환

(find #\t "The quick onyx goblin jumps over the lazy dwarf." :test #'equal) ; 대소문자 구별하여 검색
-> #\t


(find #\Z "The quick onyx goblin jumps over the lazy dwarf." :test #'equal) ; 미발견시
-> NIL

(find #\Z "The quick onyx goblin jumps over the lazy dwarf." :test #'equalp) ; 대소문자 구별 없이 검색
-> #\z


; 특정 함수를 만족시키는 문자 검색하여 문자 반환
; (digit-char-p : 문자가 숫자를 나타내는 문자인지 체크하는 함수)

(find-if #'digit-char-p "The quick onyx goblin jumps over the lazy dwarf. 1234567890") ;
-> #\1

(find-if #'digit-char-p "The quick onyx goblin jumps over the lazy dwarf. 1234567890" :from-end t) ; 뒤에서부터 검색
-> #\0


; 문자 검색 후 발견한 위치 반환

(position #\t "The quick onyx goblin jumps over the lazy dwarf." :test #'equal) ; 대소문자 구별하여 검색
-> 33

(position #\t "The quick onyx goblin jumps over the lazy dwarf." :test #'equalp) ; 대소문자 구별 없이 검색
-> 0



; 특정 함수를 만족시키는 문자 검색하여 위치를 반환

(position-if #'digit-char-p "The quick onyx goblin jumps over the lazy dwarf. 1234567890")
-> 49

(position-if #'digit-char-p "The quick onyx goblin jumps over the lazy dwarf. 1234567890" :from-end t) ; 뒤에서부터 검색
-> 58


; 문자 검색 후 발견한 갯수 반환

(count #\t "The quick onyx goblin jumps over the lazy dwarf." :test #'equal) ; 대소문자 구별하여 검색
-> 1


(count #\t "The quick onyx goblin jumps over the lazy dwarf." :test #'equalp) ; 대소문자 구별 없이 검색
-> 2



; 특정 함수를 만족시키는 문자 검색하여 갯수를 반환

(count-if #'digit-char-p "The quick onyx goblin jumps over the lazy dwarf. 1234567890")
-> 10

(count-if #'digit-char-p "The quick onyx goblin jumps over the lazy dwarf. 1234567890" :start 51) ; 특정 위치에서부터 검색
-> 5



문자열 검색

; 기본 검색
(search "the" "the quick onyx goblin jumps over the lazy dwarf.")
-> 0

; 뒤에서부터 검색
(search "the" "the quick onyx goblin jumps over the lazy dwarf." :from-end t)
-> 33

; 시작 위치를 지정하여 검색
(search "the" "the quick onyx goblin jumps over the lazy dwarf." :start2 4)
-> 33

; 뒤에서부터 시작 위치를 지정하여 검색
(search "the" "the quick onyx goblin jumps over the lazy dwarf." :end2 10 :from-end t)
-> 0

; 미발견시
(search "JUMPS" "the quick onyx goblin jumps over the lazy dwarf.")
-> NIL

; 특정 함수를 만족시키는 문자열 검색
(search "JUMPS" "the quick onyx goblin jumps over the lazy dwarf." :test #'char-equal) ; 대소문자 구별없이 문자 비교
-> 22



문자열, 숫자  사이의 변환


문자열 -> 숫자 변환 (PARSE-INTEGER 사용)
 - 두번째 리턴값은 parsing이 멈춘 위치

 - "#X23"과 같은 기수 표기법은 사용 불가

(parse-integer "37")
-> 37
2

(parse-integer "37" :start 1) ; 시작 위치를 지정
-> 7
2

(parse-integer "37" :end 1) ; 종료 위치를 지정
-> 3
1

(parse-integer "37" :radix 8) ; 진수를 지정
-> 31
2

(parse-integer " 37 ") ; space가 포함되도 괜찮다
-> 37
4

(parse-integer " 37 is thirty-seven" :junk-allowed t) ; space 외 다른 문자가 포함되는 것을 허용할 경우
-> 37
3


(parse-integer " 37 is thirty-seven") ; space 외 다른 문자를 허용하지 않을 경우
-> junk in string " 37 is thirty-seven" (에러 발생!)


문자열 -> 숫자 변화 (READ-FROM-STRING 사용)

 - 역시 두번째 리턴값은 parsing이 멈춘 위치
 - 기수 표기법은 물론 커맨드 라인에서 가능한 모든 표현이 가능
 - 심지어 문자열 안에서 함수를 실행 후 그 결과값을 사용할 수도 있다.

(read-from-string "#X23") ; 8진수 표현
-> 35
4

(read-from-string "4.5") ; 소수점
-> 4.5
3

(read-from-string "6/8") ; 분수
-> 3/4
3

(read-from-string "#C(6/8 1)") ; 복소수 (실수부 + 허수부)
-> #C(3/4 1)
9

(read-from-string "1.2e2") ; 지수 표기법
-> 120.00001
5

(defparameter a-symbol 34)
(read-from-string "a-symbol")
-> A-SYMBOL
8

(defparameter a-symbol 34)
(read-from-string "#.a-symbol") ; 변수의 실제값을 사용
-> 34
10

(read-from-string "#.(+ 1 2)") ; 함수 호출 결과값을 사용
-> 3
9


숫자 -> 문자열 변환

(write-to-string 250)
-> "250"

(write-to-string 250.02)
-> "250.02"

(write-to-string 250 :base 16) ; 16진수로
-> "FA"

(write-to-string (/ 1 3)) ; 유리수
-> "1/3"



문자열 비교

(string= "Abcd" "Abcd") ; 대소문자 구별하여 비교
-> T


(string= "Abcd" "abcd")
-> NIL


(string-equal "Abcd" "abcd") ; 대소문자 구별하지 않고 비교
-> T

(string< "aaaa" "aaab") ; "aaaa"가 "aaab"보다 작을 경우 달라지는 인덱스를 반환. 그렇지 않을 경우, NIL을 반환
-> 3

(string< "aaab" "aaaa")
-> NIL

(string-lessp "AAAA" "aaab") ; string<와 대소문자 구별을 하지 않는다는 점만 빼고 같음
-> 3

(mismatch "abcde" "bbcde" :test #'char=) ; char= 함수를 만족하지 않는 인덱스를 반환
-> 0

(mismatch "abcde" "abdde" :from-end t :test #'char=) ; 뒤에서부터 비교하여 char= 함수를 만족하지 않는 인덱스를 반환 (주의 : 0번째 문자에서 달라질 경우 1을 반환)
-> 3



참고 : http://cl-cookbook.sourceforge.net/strings.html의 내용을 바탕으로 작성했습니다.


,