・ 日本語(2バイト文字)の処理
レガシーな Auto Lisp
の文字列処理関数は、ちょっと寂しい。
(strlen) (substr) くらいしかないのです。
しかも日本語(2バイト文字)には未対応。
少しはまともになった Vuisual Lisp
でも、日本語(2バイト文字)は NG です。・・・・(~_~;)
「ならば、作ってしまえ。」ということで調べてみると。
1バイト文字(半角文字)の文字コードは、32〜126 と 161〜223
です。
(ascii)使って、1バイトと2バイトを区別すればいいわけですね。
(defun Jof_chk_cbyte( ;文字列の先頭が半角なら1をそうでないなら2を返す; str ;文字列; / a ) (setq a (ascii str)) (if (or (and (> a 31) (< a 127)) (and (> a 160) (< a 224))) 1 2) )
ところが、これを使って、文字列処理の関数を作ろうと思うと、頭がこんがらかって 「ホヘっ?」 です。
なんたって、一文字ずつ1バイトか2バイトか考えないといけないわけですから・・・・(-_-;)
そこで思いついたのが、「文字列を一文字ずつのリストにしてから処理したら」ってことです。
我ながら名案 (^_^)v
「多少遅くなろうが、動けばいいのさ。」
(defun Jof_str2clst( ;文字列を一文字ごとアトムにしてリスト化; str ;文字列; / byte lst_str) (while (not (= str "")) (setq byte (Jof_chk_cbyte str)) (cond ((= byte 1) (setq lst_str (cons (substr str 1 1) lst_str)) (setq str (substr str 2))) ((= byte 2) (setq lst_str (cons (substr str 1 2) lst_str)) (setq str (substr str 3))) ) ) (reverse lst_str) )(defun Jof_clst2str( ;文字のリストを文字列に変換; lst_str ;文字のリスト; / ) (apply 'strcat lst_str) )
あとは、リスト処理の関数使えば、いろいろできそうです。
というわけで、作った文字列処理関数セット
(Jo_str_set.lsp) を、お蔵入りツールにもアップしときました。
すべて2バイト文字対応です。
これだけでは、コマンドとして利用はできませんが、他のプログラムからコールするファンクションとしてご利用ください。
;***********************************************************************;
;文字列処理関数セット 2バイト文字対応 ;
; 更新履歴 ;
; 2004/07/11 Jof_instr2 のバグフィックス ;
; 2004/07/12 Jof_bsubstr2 の追加 ;
; 2004/06/23 by Kamijo ;
;***********************************************************************;
;///////////////////////////////////////////////////////////////////////;
;文字列処理関数サブセット ;
;///////////////////////////////////////////////////////////////////////;
;***********************************************************************;
;文字列の先頭が半角なら1をそうでないなら2を返す ;
;***********************************************************************;
(defun Jof_chk_cbyte(
str ;文字列;
/ a )
(setq a (ascii str))
(if (or (and (> a 31) (< a 127)) (and (> a 160) (< a 224))) 1 2)
)
;***********************************************************************;
;文字列を一文字ごとアトムにしてリスト化 ;
;***********************************************************************;
(defun Jof_str2clst(
str ;文字列;
/ byte lst_str)
(while (not (= str ""))
(setq byte (Jof_chk_cbyte str))
(cond
((= byte 1)
(setq lst_str (cons (substr str 1 1) lst_str))
(setq str (substr str 2)))
((= byte 2)
(setq lst_str (cons (substr str 1 2) lst_str))
(setq str (substr str 3)))
)
)
(reverse lst_str)
)
;***********************************************************************;
;文字のリストを文字列に変換 ;
;***********************************************************************;
(defun Jof_clst2str(
lst_str ;文字のリスト;
/ )
(apply 'strcat lst_str)
)
;***********************************************************************;
;リストのn番目からx個の要素をリストで返す ;
;***********************************************************************;
(defun Jof_lstmid(
lst ;リスト;
n ;n番目から 先頭は0番目;
x ;x個;
/ len ret)
(setq len (length lst))
(repeat (min n len)
(setq lst (cdr lst))
)
(setq len (length lst))
(repeat (min x len)
(setq ret (cons (car lst) ret))
(setq lst (cdr lst))
)
(reverse ret)
)
;***********************************************************************;
;リストのn番目からx個の要素を削除して返す ;
;***********************************************************************;
(defun Jof_lstmid_del(
lst ;リスト;
n ;n番目から 先頭は0番目;
x ;x個;
/ len ret)
(setq len (length lst))
(repeat (min n len)
(setq ret (cons (car lst) ret))
(setq lst (cdr lst))
)
(setq len (length lst))
(repeat (min x len)
(setq lst (cdr lst))
)
(setq len (length lst))
(repeat len
(setq ret (cons (car lst) ret))
(setq lst (cdr lst))
)
(reverse ret)
)
;***********************************************************************;
;リストをn番目より前と以後にわけて返す ;
;***********************************************************************;
(defun Jof_lst_div(
lst ;リスト;
n ;n番目 先頭は0番目;
/ len ret1 ret2 )
(setq len (length lst))
(repeat (min n len)
(setq ret1 (cons (car lst) ret1))
(setq lst (cdr lst))
)
(setq len (length lst))
(repeat len
(setq ret2 (cons (car lst) ret2))
(setq lst (cdr lst))
)
(list (reverse ret1) (reverse ret2))
)
;///////////////////////////////////////////////////////////////////////;
;以下ユーザーがコールするファンクション ;
;(サブセット以外のファンクションをコールしているものもあるので注意) ;
;///////////////////////////////////////////////////////////////////////;
;***********************************************************************;
;文字列の長さを返す ;
; (strlen の2バイト文字対応版) ;
;***********************************************************************;
(defun Jof_strlen2(
str ;文字列;
/ )
(length (Jof_str2clst str))
)
;***********************************************************************;
;文字列の左から指定した文字数分の文字列を返す ;
; (VBAの Left みたいなのです) ;
;***********************************************************************;
(defun Jof_strleft2(
str ;文字列;
len ;指定した文字数;
/ lst_str)
(setq lst_str (Jof_str2clst str))
(setq lst_str (Jof_lstmid lst_str 0 len))
(Jof_clst2str lst_str)
)
;***********************************************************************;
;文字列の右から指定した文字数分の文字列を返す ;
; (VBAの Right みたいなのです) ;
;***********************************************************************;
(defun Jof_strright2(
str ;文字列;
len ;指定した文字数;
/ lst_str)
(setq lst_str (reverse (Jof_str2clst str)))
(setq lst_str (reverse (Jof_lstmid lst_str 0 len)))
(Jof_clst2str lst_str)
)
;***********************************************************************;
;文字列の指定した位置から指定した文字数分の文字列を返す ;
; (substr の2バイト文字対応版) ;
;***********************************************************************;
(defun Jof_substr2(
str ;文字列;
start ;指定した位置 先頭は1番目;
len ;指定した文字数;
/ lst_str)
(setq lst_str (Jof_str2clst str))
(setq lst_str (Jof_lstmid lst_str (1- start) len))
(Jof_clst2str lst_str)
)
;***********************************************************************;
;文字列を検索し、その最初の文字位置を返す ない場合はnil 先頭は1番目 ;
; (VBAの InStr みたいなのです) ;
;***********************************************************************;
(defun Jof_instr2(
start ;検索スタート位置 先頭は1番目;
str1 ;対象文字列;
str2 ;検索文字列;
/ lst_str1 lst_str1d lst_str1dd lst_str2 lst_str2d len flg)
(setq lst_str1 (reverse (Jof_str2clst str1)))
(setq len (- (length lst_str1) (1- start)))
(setq lst_str1d (reverse (Jof_lstmid lst_str1 0 len)))
(setq lst_str2 (Jof_str2clst str2))
(setq start nil)
(while (and lst_str1d (not start))
(setq lst_str1d (member (car lst_str2) lst_str1d))
(setq flg (if (>= (length lst_str1d) (length lst_str2)) T nil))
(setq lst_str1dd (setq lst_str1d (cdr lst_str1d)))
(setq lst_str2d (cdr lst_str2))
(while (and flg lst_str2d)
(if (= (car lst_str1dd) (car lst_str2d))
(progn
(setq lst_str1dd (cdr lst_str1dd))
(setq lst_str2d (cdr lst_str2d))
)
(setq flg nil)
)
)
(setq start (if flg (1+ (- (length lst_str1) (+ (length lst_str1dd) (length lst_str2)))) nil))
)
start
)
;***********************************************************************;
;文字列を検索し、その文字列を削除して返す ;
;***********************************************************************;
(defun Jof_instr_del2(
start ;検索スタート位置 先頭は1番目;
str1 ;対象文字列;
str2 ;検索文字列;
multi ;連続実行フラグ nil:1回 / T:繰返し実行;
/ lst_str n x ret )
(setq n (Jof_instr2 start str1 str2))
(setq lst_str (Jof_str2clst str1))
(setq x (Jof_strlen2 str2))
(if (and n x)
(progn
(setq lst_str (Jof_lstmid_del lst_str (1- n) x))
(setq ret (Jof_clst2str lst_str))
(if multi
(Jof_instr_del2 start ret str2 T)
ret
)
)
str1
)
)
;***********************************************************************;
;文字列の指定した位置から指定した文字数分削除して返す ;
;***********************************************************************;
(defun Jof_substr_del2(
str ;対象文字列;
start ;指定した位置 先頭は1番目;
len ;指定した文字数;
/ lst_str)
(setq lst_str (Jof_str2clst str))
(setq lst_str (Jof_lstmid_del lst_str (1- start) len))
(Jof_clst2str lst_str)
)
;***********************************************************************;
;文字列を検索し、その文字列を置き換える ;
;***********************************************************************;
(defun Jof_instr_chg2(
start ;検索スタート位置 先頭は1番目;
str1 ;対象文字列;
str2 ;検索文字列;
str3 ;置換文字列;
multi ;連続実行フラグ nil:1回 / T:繰返し実行;
/ n x f lst_str ret)
(setq n (Jof_instr2 start str1 str2))
(setq lst_str (Jof_str2clst str1))
(setq x (Jof_strlen2 str2))
(setq f (if (= str2 str3) nil t))
(if (and n x f)
(progn
(setq lst_str (Jof_lstmid_del lst_str (1- n) x))
(setq lst_str (Jof_lst_div lst_str (1- n)))
(setq ret (strcat (Jof_clst2str (car lst_str)) str3 (Jof_clst2str (cadr lst_str))))
(if multi
(Jof_instr_chg2 start ret str2 str3 T)
ret
)
)
str1
)
)
;***********************************************************************;
;文字列の指定した位置から指定した文字数分削除し、文字列を置き換える ;
; (VBAの Mid みたいなのです) ;
;***********************************************************************;
(defun Jof_substr_chg2(
str1 ;対象文字列;
start ;指定した位置 先頭は1番目;
len ;指定した文字数;
str2 ;置換文字列;
/ n x lst_str )
(setq lst_str (Jof_str2clst str1))
(setq lst_str (Jof_lstmid_del lst_str (1- start) len))
(setq lst_str (Jof_lst_div lst_str (1- start)))
(strcat (Jof_clst2str (car lst_str)) str2 (Jof_clst2str (cadr lst_str)))
)
;***********************************************************************;
;文字先頭の空白を削除 ;
; (VBAの LTrim みたいなのです) ;
;***********************************************************************;
(defun Jof_strtrim_L2(
str ;対象文字列;
/ lst_str)
(setq lst_str (Jof_str2clst str))
(while (or (= (car lst_str) " ") (= (car lst_str) " "))
(setq lst_str (cdr lst_str))
)
(Jof_clst2str lst_str)
)
;***********************************************************************;
;文字末尾の空白を削除 ;
; (VBAの RTrim みたいなのです) ;
;***********************************************************************;
(defun Jof_strtrim_R2(
str ;対象文字列;
/ lst_str)
(setq lst_str (Jof_str2clst str))
(setq lst_str (reverse lst_str))
(while (or (= (car lst_str) " ") (= (car lst_str) " "))
(setq lst_str (cdr lst_str))
)
(setq lst_str (reverse lst_str))
(Jof_clst2str lst_str)
)
;***********************************************************************;
;文字前後の空白を削除 ;
; (VBAの Trim みたいなのです) ;
;***********************************************************************;
(defun Jof_strtrim2(
str ;対象文字列;
/ )
(Jof_strtrim_R2 (Jof_strtrim_L2 str))
)
;***********************************************************************;
;文字列を指定した区切り文字で分割し、リストにする ;
;***********************************************************************;
(defun Jof_str2slst2(
str ;対象文字列;
cha ;区切り文字;
/ lst_str lst_ret lst_a)
(setq lst_str (Jof_str2clst str))
(while lst_str
(setq lst_a nil)
(while (and lst_str (not (= cha (car lst_str))))
(setq lst_a (cons (car lst_str) lst_a))
(setq lst_str (cdr lst_str))
)
(setq lst_ret (cons (Jof_clst2str (reverse lst_a)) lst_ret))
(setq lst_str (cdr lst_str))
)
(reverse lst_ret)
)
;***********************************************************************;
;文字列のリストを指定した区切り文字でつないで文字列にする ;
;***********************************************************************;
(defun Jof_slst2str2(
lst ;対象リスト;
cha ;区切り文字;
/ flg str_ret)
(setq flg 1)
(foreach n lst (if (/= 'STR (type n)) (setq flg 0)))
(if (= flg 1)
(progn
(setq str_ret (car lst))
(foreach n (cdr lst) (setq str_ret (strcat str_ret cha n)))
)
(princ "\nリストの中に文字列以外の要素が含まれているため、処理できません")
)
str_ret
)
;***********************************************************************;
;文字列の指定した位置から指定バイト数分の文字列を返す ;
; (substr の2バイト文字対応バイト指定版) ;
;***********************************************************************;
(defun Jof_bsubstr2(
str ;文字列;
start ;指定した位置(バイト指定) 先頭は1バイト目;
byte ;指定したバイト数;
/ n lst_str nn lst_ret)
(setq lst_str (Jof_str2clst str))
(setq n 0)
(while (and (<= (+ n (setq nn (Jof_chk_cbyte (car lst_str)))) (1- start)) (< start (strlen str)))
(setq n (+ n nn))
(setq lst_str (cdr lst_str))
)
(setq nn (- (strlen str) n))
(setq n 0)
(while (and (< n byte) (< n nn))
(setq n (+ n (Jof_chk_cbyte (car lst_str))))
(setq lst_ret (cons (car lst_str) lst_ret))
(setq lst_str (cdr lst_str))
)
(Jof_clst2str (reverse lst_ret))
)