去年作ったモノですが、気がつくと結構あちこちで使っていた。
手元ではLinux版のOracle9iで動作しています。
001 | /* Oracle用 ISBNパッケージ |
002 | 10桁と13桁のISBNを相互に変換する。チェックデジットの計算もできる。 |
004 |
005 | $Id: pkg_isbn.sql,v 1.5 2005/11/07 02:12:27 ymo Exp $ |
006 | */ |
007 |
008 | CREATE OR REPLACE PACKAGE ISBN_PKG AS |
009 | /* |
010 | || 入力されたISBNをチェックデジットを付けたりいろいろする。 |
011 | || 10桁を13桁に直したり、13桁を10桁に直すこともできる。 |
012 | */ |
013 | FUNCTION ISBN10(i_isbn IN varchar2) RETURN varchar2; |
014 | FUNCTION ISBN13(i_isbn IN varchar2) RETURN varchar2; |
015 |
016 | /* |
017 | || 入力されたISBNをチェックデジットを抜いた大事なところだけにする。 |
018 | */ |
019 | FUNCTION REGULATE_ISBN(i_isbn IN varchar2) RETURN varchar ; |
020 |
021 | /* |
022 | || 10桁版チェックデジットを計算して返す |
023 | || 入力は9文字、10文字、13文字のどれか |
024 | */ |
025 | FUNCTION CHECK_DEGIT10( i_isbn IN varchar2) RETURN char ; |
026 |
027 | /* |
028 | || 13桁版ISBNのチェックデジットを計算して返す。 |
029 | || 入力は9文字、10文字、13文字のどれか |
030 | */ |
031 | FUNCTION CHECK_DEGIT13( i_isbn IN varchar2) RETURN char ; |
032 |
033 | END ISBN_PKG; |
034 | / |
035 |
036 | ---------------------------------------------------------- |
037 | -- PACKAGE BODY |
038 | ---------------------------------------------------------- |
039 | CREATE OR REPLACE PACKAGE BODY ISBN_PKG AS |
040 |
041 | ---------------------------------------------------------- |
042 | -- F ISBN10 |
043 | ---------------------------------------------------------- |
044 | FUNCTION ISBN10(i_isbn IN varchar2) RETURN varchar2 |
045 | IS |
046 | sRaw varchar2(9); |
047 | BEGIN |
048 | sRaw := REGULATE_ISBN(i_isbn); |
049 | RETURN sRaw || CHECK_DEGIT10(sRaw); |
050 | END ; |
051 |
052 | ---------------------------------------------------------- |
053 | -- F ISBN13 |
054 | ---------------------------------------------------------- |
055 | FUNCTION ISBN13(i_isbn IN varchar2) RETURN varchar2 |
056 | IS |
057 | sRaw varchar2(9); |
058 | BEGIN |
059 | sRaw := REGULATE_ISBN(i_isbn); |
060 | RETURN '978' || sRaw || CHECK_DEGIT13(sRaw); |
061 | END ; |
062 |
063 | ---------------------------------------------------------- |
064 | -- F REGULATE_ISBN |
065 | ---------------------------------------------------------- |
066 | FUNCTION REGULATE_ISBN(i_isbn IN varchar2) RETURN varchar |
067 | IS |
068 | buf varchar2(20); |
069 | sRaw varchar2(9); |
070 | BEGIN |
071 | buf := SUBSTRB( REPLACE ( REPLACE ( UPPER (TRIM(i_isbn)), 'ISBN' ), '-' ),1,20); |
072 | sRaw := TRIM(SUBSTRB(buf,1,9)); |
073 |
074 | IF LENGTH(buf) = 9 THEN |
075 | sRaw := SUBSTRB(buf, 1, 9); |
076 | END IF; |
077 | IF LENGTH(buf) = 10 THEN |
078 | sRaw := SUBSTRB(buf, 1, 9); |
079 | END IF; |
080 | IF LENGTH(buf) = 13 THEN |
081 | sRaw := SUBSTRB(buf, 4, 9); |
082 | END IF; |
083 |
084 | RETURN sRaw; |
085 | END ; |
086 |
087 | ---------------------------------------------------------- |
088 | -- F CHECK_DEGIT10 |
089 | ---------------------------------------------------------- |
090 | FUNCTION CHECK_DEGIT10(i_isbn IN varchar2) RETURN char |
091 | IS |
092 | vWeight PLS_INTEGER; |
093 | vSum PLS_INTEGER; |
094 | vResult PLS_INTEGER; |
095 | sRaw varchar2(9); |
096 | BEGIN |
097 | sRaw := REGULATE_ISBN(i_isbn); |
098 | vWeight := 10; |
099 | vSum := 0; |
100 | FOR i IN 1..LENGTH(sRaw) |
101 | LOOP |
102 | vSum := vSum + vWeight * to_number(SUBSTR(sRaw, i, 1)); |
103 | vWeight := vWeight - 1; |
104 | END LOOP; |
105 | vResult := 11 - (vSum MOD 11); |
106 | if vResult = 10 THEN |
107 | RETURN 'X' ; |
108 | END IF; |
109 | if vResult = 11 THEN |
110 | RETURN '0' ; |
111 | END IF; |
112 | RETURN SUBSTR(to_char(vResult),1,1); |
113 |
114 | EXCEPTION |
115 | WHEN OTHERS THEN |
116 | RETURN 'E' ; |
117 | END ; |
118 |
119 | ---------------------------------------------------------- |
120 | -- F CHECK_DEGIT13 |
121 | ---------------------------------------------------------- |
122 | FUNCTION CHECK_DEGIT13(i_isbn IN varchar2) RETURN char |
123 | IS |
124 | vSum1 PLS_INTEGER; |
125 | vSum2 PLS_INTEGER; |
126 | vResult PLS_INTEGER; |
127 | r char ; |
128 | sRaw varchar2(12); |
129 | BEGIN |
130 | sRaw := '978' || REGULATE_ISBN(i_isbn); |
131 |
132 | vSum1 := 0; |
133 | vSum2 := 0; |
134 |
135 | FOR i IN 1..LENGTH(sRaw) |
136 | LOOP |
137 | IF MOD(i,2) = 1 THEN |
138 | vSum1 := vSum1 + to_number(SUBSTR(sRaw, i, 1)); |
139 | ELSE |
140 | vSum2 := vSum2 + to_number(SUBSTR(sRaw, i, 1)); |
141 | END IF; |
142 | END LOOP; |
143 |
144 | vResult := vSum1 + (vSum2 * 3); |
145 | vResult := 10 - to_number(SUBSTR(to_char(vResult),length(to_char(vResult)),1)); |
146 | IF vResult > 9 THEN |
147 | RETURN '0' ; |
148 | ELSE |
149 | RETURN SUBSTR(to_char(vResult),1,1); |
150 | END IF; |
151 |
152 | EXCEPTION |
153 | WHEN OTHERS THEN |
154 | RETURN 'E' ; |
155 | END ; |
156 |
157 | END ISBN_PKG; |
158 | / |
159 |
160 |
161 | /** |
162 | SELECT 'Answer => 4798108545: ' ||ISBN_PKG.ISBN10( '479810854' ) FROM DUAL; |
163 | SELECT 'Answer => 9784798108544: ' ||ISBN_PKG.ISBN13( '4798108545' ) FROM DUAL; |
164 |
165 | SELECT 'Answer => 4949999087: ' || ISBN_PKG.ISBN10( '494999908' ) FROM DUAL; |
166 | SELECT 'Answer => 9784949999083: ' || ISBN_PKG.ISBN13( '494999908' ) FROM DUAL; |
167 |
168 |
169 | SELECT ISBN_PKG.CHECK_DEGIT10( '4798108545' ) FROM DUAL; |
170 | SELECT ISBN_PKG.CHECK_DEGIT10( '494999908' ) FROM DUAL; |
171 | SELECT ISBN_PKG.CHECK_DEGIT10( 'ISBN4-9499-9908' ) FROM DUAL; |
172 | SELECT ISBN_PKG.CHECK_DEGIT10( '9784883810246' ) FROM DUAL; |
173 | SELECT ISBN_PKG.CHECK_DEGIT10( '9784883810161' ) FROM DUAL; |
174 | SELECT ISBN_PKG.CHECK_DEGIT10( '9784431711438' ) FROM DUAL; |
175 |
176 | SELECT ISBN_PKG.CHECK_DEGIT13( '4798108545' ) FROM DUAL; |
177 | SELECT ISBN_PKG.CHECK_DEGIT13( '494999908' ) FROM DUAL; |
178 | SELECT ISBN_PKG.CHECK_DEGIT13( 'ISBN4-9499-9908' ) FROM DUAL; |
179 | */ |