Journal Articles
Browse in : |
All
> Journals
> CVu
> 115
(21)
All > Topics > Programming (877) Any of these categories - All of these categories |
Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.
Title: ISBN Numbers
Author: Administrator
Date: 03 August 1999 13:15:32 +01:00 or Tue, 03 August 1999 13:15:32 +01:00
Summary:
Body:
The problem:- validate a number input by a user as an ISBN number The solution[1] :- A C script
This (flawed) program came about when I found out how ISBN numbers were created.
Some samples:-
0-672-31022-8 1-55828-552-0 0-88022-519-X
The format for the numbers is not as important as the calculation. After taking out the hyphens there are ten digits, and each one represents its own value, i.e., 0 = 0, 1 = 1, 2 = 2, etc. X is the symbol for the value ten[2].
Starting from the left, each number is multiplied by a value, starting with 10 and decrementing by 1 for each successive digit, so the second number is multiplied by nine, the third by eight etc, and the tenth by 1. All 10 numbers are then added together and the result must be divisible by eleven, or it is not a true ISBN number.
The first thing I had to do was accept a number from the user in the ISBN format, and strip out all the hyphens. As there is a mixture of characters, and more importantly, some would be kept while others rejected, and the input was from the keyboard, I decided to capture the input into a function, validate(int). The number is tested and the user is given the result. The first exercise was to restrict what the user could enter to only three items, digits 0 - 9, hyphens and the letter X, in either lower or upper case.
Some constant declarations
#define ISBN 14 #define MAX 10 enum { FALSE, TRUE };
Here is the validate function:-
void validate(int length){ int loop, reply = 1; char input[ISBN]; char output[ISBN]; char keystroke = '\0'; int valid; /* enter characters until the return is hit * which will terminate the input to be checked */ for(loop = 0; (loop < length) && keystroke != 13; loop++) { do { valid = TRUE; keystroke = getch(); input[loop] = keystroke; /* check that only numbers 0 to 9, * RETURN, character's '-' 'x' or 'X' are entered */ if(keystroke < 48 && keystroke != '-' && keystroke != 13 || keystroke > 57 && keystroke != 'x' && keystroke != 'X') valid = FALSE; /* if the character is unacceptable * let the user know and allow them to continue inputting */ if(valid == FALSE) printf("\a"); } while(valid == FALSE); printf("%c", input[loop]); } input[loop] = '\0';
Before the function ends there are three more jobs to do, firstly call a function for the user to check that they have input the number correctly now that it has been validated as a true ISBN category number[3]
check(input);
then make a copy of the input, this dummy has been created because the input is altered by the check function so the output would be numbers without the dashes
strcpy(output, input);
and finally call a function to remove the dashes from the string so that it can be treated as a number
reply = dashes(output);
Now that the user is happy with the number that they have entered after it has been checked to see that it fits in with the rules, the dashes have to be removed so that the string can be converted to a number so that it can be checked to see if it is divisible by eleven
int dashes(char *start){ int number, result = 0; int loop, index = 0; clrscr(); for(loop = 0; loop < ISBN; loop++) { if(start[index] == '-') strcpy(&start[index], &start[index + 1]); index++; }
call a function to multiply each element by an incrementing number, totalling all the elements and returning the total so that it can be tested for division by eleven.
number = isbntest(start); result = (number % ISBN); if(result != 0) { puts("This is not a valid ISBN number"); puts("press any key to continue. . . "); getch(); }
the reason why the OK message is not here is that there are no longer any dashes in the string so presentation on the screen would not look so good.
All that is left to do is test the number against the rules, this function does a lot of work despite its simplicity it takes each element of the array and multiplies it by count which then decrements through the loop
int isbntest(char *start) { int loop, sum = 0, result = 0; int count = MAX, end[MAX] = { 1,1,1,1,1,1,1,1,1,1 }; clrscr(); for(loop = 0; loop < MAX; loop++) { if(start[loop] == '0') end[loop] = (0 * count); if(start[loop] == '1') end[loop] = (1 * count); if(start[loop] == '2') end[loop] = (2 * count); if(start[loop] == '3') end[loop] = (3 * count); if(start[loop] == '4') end[loop] = (4 * count); if(start[loop] == '5') end[loop] = (5 * count); if(start[loop] == '6') end[loop] = (6 * count); if(start[loop] == '7') end[loop] = (7 * count); if(start[loop] == '8') end[loop] = (8 * count); if(start[loop] == '9') end[loop] = (9 * count); if(start[loop] == 'x' || start[loop] == 'X') end[loop] = (10 * count); count--; } for(loop = 0; loop < MAX; loop++) sum += end[loop]; result = (sum % 11); return result; }
All the contents of the loop are added together and the final sum is tested to see if it is a multiple of eleven to prove that it is a true ISBN number.
The full program is available if required, and I hope this has been useful for anyone in their current work, or if it brings any other items to mind, or if you know a better way to check for ISBN's. Okay, truth time, I wrote this in February 1998, it is the last C program that I produced at the end of my first year learning to program, and I had just started to learn C++ [which I am still trying to do] ;-) I can see some mistakes with the above, i.e.,
-
the enum is unnecessary as there is a standard bool type now,
-
the mixture of numbers, letters and symbols here is extremely poor
if(keystroke < 48 && keystroke != '-' && keystroke != 13 || keystroke > 57 && keystroke != 'x' && keystroke != 'X') valid = FALSE;
-
the function dashes(char*) should be called removeDashes(char*),
-
perhaps a switch would be better than all those if's in isbnTest(char*)
however, its the mistakes that I cannot see that I need help with, and why I read C Vu and Overload.
Thanks, Paul. There are several defects in your code. I have highlighted one in the footnotes I have added, but there are others. Not least is that some people use spaces to format their ISBN numbers, not strictly correct but I think it would be picky to reject a potential ISBN simply because of that. Another problem is that your solution requires raw keyboard processing which is not always easily available.
I suggest that the problem should split into two parts: capturing a data-string which is a potential ISBN and then validating it. In the first part, keyboard input is only one of several potential methods (e.g. get data from a database). In the second part I think that a clear distinction should be made between the body of the ISBN and the final check-digit. Perhaps allowance should also be made for SBNs (they have eight not nine digits in the body and can be converted to ISBNs by prefixing them with a 0). I think much could be done to produce a cleaner solution, but let the readers have a go first.
And what about ISSNs? Actually I do not know if there are any validation rules for these.
[1] Writing a program to do this was one of my standard pupil exercises in the days when I was a teacher. Of course my students wrote the code in Forth ☺ I feel that this sort of task is well suited to scripting languages. I would be happy to publish alternative solutions in the language of your choice: C, C++. Java, Python, awk etc. I would also encourage the multi-lingual readers to do a comparison between ease of solution in several languages.
[2] X can only occur as the final (check-)digit
[3] Astute readers will realise that there is a slight flaw in this algorithm. How should we eliminate 'X' as anything other than a final check-digit.
Notes:
More fields may be available via dynamicdata ..