・ 日本語(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)) )