国际标准书号(International Standard Book Number),简称 ISBN ,是专门为识别图书等文献而设计的国际编号。2007 年 1 月 1 日之前,ISBN 由 10 位数字组成,包括四个部分:组号(国家、地区、语言的代号),出版者号,书序号和检验码。2007 年 1 月 1 日起,实行新版 ISBN,新版 ISBN 由 13 位数字组成。新版 ISBN 编码增加了 EAN·UCC 前缀,这是为了与国际条形码编码 EAN·UCC 系统接轨。 本题请实现一个
ISBN-10
(旧版 10 位 ISBN )到ISBN-13
(新版 13 位 ISBN )码的转换工具。
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── css
│ └── style.css
├── effect.gif
├── images
│ ├── check-one.png
│ ├── close-one.png
│ └── fail-picture.png
├── index.html
└── js
├── JsBarcode.ean-upc.min.js
├── index.js
└── vue.min.js
其中:
css/style.css
是样式文件。index.html
是主页面。images
文件夹内包含了页面使用的 icon。js/JsBarcode.ean-upc.min.js
是项目使用的条形码生成库。js/index.js
是页面 js
文件。js/vue.min.js
是 vue
文件。effect.gif
是页面最终的效果图。注意:打开环境后发现缺少项目代码,请复制下述命令至命令行进行下载:
cd /home/project
wget https://labfile.oss.aliyuncs.com/courses/18213/ISBN.zip
unzip ISBN.zip && rm ISBN.zip
在浏览器中预览 index.html
页面效果如下:
请在 js/index.js
文件中补全代码,具体需求如下:
补充 getNumbers
函数,剔除输入参数 str
中除了数字和大写 X
之外的其他字符,将其转换为只有纯数字和大写 X
字母的字符串。
补充 validISBN10
函数,判断输入参数 isbn
是否是一个有效的 ISBN-10
字符串,并将判断结果(true
或 false
)返回。有效的 ISBN-10
判断方法如下:
有效的 ISBN-10
字符串是只有纯数字和大写 X
字母的字符串,其前九位是 0-9 之间的任意数字,最后一位校验位的值取决于前九位数字。
校验位计算方法:用 1-9 这 9 个数依次乘以前面的 9 位数,然后求它们的和除以 11 的余数。如果余数为 10,则校验码用 X
表示,否则,校验码用该余数表示。
以 7-5600-3879-4
为例,它的前 9 位数是 7、5、6、0、0、3、8、7、9,则其校验码的计算过程如下:
1x7+2x5+3x6+4x0+5x0+6x3+7x8+8x7+9x9
= 7+10+18+0+0+18+56+56+81
= 246
246 % 11 = 4
因此,这个 ISBN-10 字符串的校验码就是4。
以 2-5600-3879-X
为例,它的前 9 位数是 2、5、6、0、0、3、8、7、9,则其校验码的计算过程如下:
1x2+2x5+3x6+4x0+5x0+6x3+7x8+8x7+9x9
= 2+10+18+0+0+18+56+56+81
= 241
241 % 11 = 10
因此,这个 ISBN-10 字符串的校验码就是X。
补充 ISBN10To13
函数,将输入参数 isbn
(一个有效的 ISBN-10
字符串) 转化为对应的 ISBN-13
字符串,并将转化后的字符串返回。转化步骤如下:
将 ISBN-10
字符串的最后一位校验位去掉,剩下前九个数字。
在字符串开头增加 978 三个数字,获得长度为 12 的数字字符串。
计算最后一位校验位。ISBN-13
的校验码计算规则如下:用1分别乘书号的前12位中的奇数位, 用3乘以偶数位,然后求它们的和除以10的余数,最后用10减去这个余数,就得到了校验码。如果余数为0,则校验码为0。
比如,7-5600-3879-4 在 ISBN-13 中,就是 978-7-5600-3879-7。它的校验码计算方法如下:
9x1+7x3+8x1+7x3+5x1+6x3+0x1+0x3+3x1+8x3+7x1+9x3
= 9+21+8+21+5+18+0+0+3+24+7+27
= 143
143 % 10 = 3
10 - 3 = 7
因此,这个 ISBN-13 字符串的校验码就是7。
下面是几个有效的 ISBN-10
号码,可供测试页面使用:
上述 3 个需求正确实现后页面的最终效果见文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
// 将用户输入的带分隔符的 isbn 字符串转换只有纯数字和大写 X 字母的字符串
// 入参 str 为转换为包含任意字符的字符串
function getNumbers(str) {
// TODO: 待补充代码
return str.replace(/[^\dX]/g,'')
}
// 验证当前 ISBN10 字符串是否有效
// 入参 str 为待判断的只有纯数字和大写 X 字母的字符串
/**
*
* @param {String} str
*/
function validISBN10(str) {
// TODO: 待补充代码
if(!/^\d{9}[\dX]$/.test(str)){
return false
}
let arr = str.slice(0,9).split('')
let sum = arr.map(Number).reduce((acc,cur,idx)=>{
return acc + cur*(idx+1)
},0)
let check = (sum%11 == 10 ? "X" : String(sum%11))
return check == str[str.length-1]
}
// 将用户输入的 ISBN-10 字符串转化为 ISBN-13 字符串
// 入参 isbn 为有效的 ISBN-10 字符串
function ISBN10To13(isbn) {
// TODO: 待补充代码
let str = '978'+isbn.slice(0,9)
let sum = str.split('').map(Number).reduce((acc,cur,idx)=>{
return acc + ((idx+1)%2==0?cur*3:cur)
},0)
let check = (sum%10==0?'0':String(10-sum%10))
return str + check
}
// 测试用例
console.log(getNumbers("7-5600-3879-4")); // 7560038794
console.log(getNumbers("7 5600 3879 4")); // 7560038794
console.log(validISBN10("7560038794")); // true
console.log(validISBN10("7560038793")); // false
console.log(validISBN10("756003879")); // false
console.log(validISBN10("756003879004")); // false
console.log(ISBN10To13("7560038794")); // 9787560038797
console.log(ISBN10To13("3598215088")); // 9783598215087
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>ISBN 转换与生成</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
</head>
<body>
<div id="app">
<header>
<h1>ISBN转换工具</h1>
</header>
<div class="container">
<div class="input">
<h3>ISBN 10</h3>
<textarea placeholder="请输入ISBN-10号码" v-model="isbn" @input="outputImage"></textarea>
<div class="prompt" v-if="isbn">
<img src="images/check-one.png" v-if="validISBN">
<img src="images/close-one.png" v-else>
</div>
</div>
<div class="output">
<h3>转换结果</h3>
<p v-if="validISBN">{{ convertedISBN }}</p>
<p v-else>请输入有效的ISBN-10号码</p>
<div>
<img src="images/fail-picture.png" id="error" v-if="!validISBN">
<img id="barcode"></img>
</div>
</div>
</div>
</div>
</body>
<script src="js/vue.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/JsBarcode.ean-upc.min.js"></script>
<script src="js/index.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
isbn: '',
},
computed: {
// 将ISBN10转化为ISBN13
convertedISBN() {
if (this.validISBN) {
return ISBN10To13(this.isbnNums)
} else {
return ''
}
},
// 判断当前ISBN是否是有效的ISBN10
validISBN() {
return validISBN10(this.isbnNums)
},
// 过滤掉用户输入中的分隔符
isbnNums() {
return getNumbers(this.isbn)
}
},
methods: {
outputImage() {
if (this.convertedISBN) {
JsBarcode("#barcode", this.convertedISBN)
}
}
},
});
</script>
</html>
<代码功能概述>
这段 HTML 代码创建了一个使用 Vue.js 框架的网页,用于实现 ISBN - 10 到 ISBN - 13 的转换,并生成对应的条形码。
<详细解释>
meta charset="UTF-8"
:设置字符编码为 UTF - 8。meta name="viewport"
:设置页面在移动设备上的显示方式。link rel="stylesheet"
:引入外部 CSS 文件进行样式设置。<div id="app">
:Vue 实例的挂载点。<header>
:显示页面标题。<div class="input">
:包含一个文本框用于输入 ISBN - 10 号码,以及根据输入的有效性显示不同的图标。<div class="output">
:根据输入的有效性显示转换后的 ISBN - 13 号码或错误提示,并生成对应的条形码。vue.min.js
:引入 Vue.js 框架。JsBarcode.ean-upc.min.js
:引入条形码生成库。js/index.js
:引入自定义的 JavaScript 文件。el: "#app"
:将 Vue 实例挂载到 id
为 app
的元素上。data
:定义一个响应式数据 isbn
,用于存储用户输入的 ISBN - 10 号码。computed
:定义三个计算属性: convertedISBN
:根据输入的有效性将 ISBN - 10 转换为 ISBN - 13。validISBN
:判断输入的 ISBN - 10 是否有效。isbnNums
:过滤掉用户输入中的分隔符。methods
:定义一个方法 outputImage
,用于在输入有效时生成条形码。* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #eee;
}
header {
color: white;
background-color: #bbb;
text-align: center;
padding: 1rem;
margin-bottom: 1rem;
}
.container {
margin: auto;
margin-top: 5rem;
width: 600px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.input,
.output {
background-color: white;
padding: 1rem;
border: 1px solid #bbb;
position: relative;
}
.input h3 {
margin-bottom: 1rem;
}
textarea {
resize: none;
padding: 0.5rem;
width: 250px;
height: 150px;
font-size: 1.1rem;
}
textarea:focus {
outline: none;
}
.input .prompt {
position: absolute;
bottom: 1.6rem;
left: 1.25rem;
color: rgba(208, 2, 27, 0.9);
font-size: 0.9rem;
}
.prompt img {
width: 30px;
height: 30px;
}
.output img {
position: absolute;
width: 250px;
height: 150px;
background-color: white;
transform: translateX(-50%);
left: 50%;
}
#error {
z-index: 2;
}
.output p {
width: 100%;
text-align: center;
}
.output h3 {
margin-bottom: 0.5rem;
}
<代码功能概述>
这段 CSS 代码用于对 HTML 页面进行样式设置,使页面布局更加美观。
<详细解释>
* { margin: 0; padding: 0; box-sizing: border-box; }
:清除所有元素的默认边距和内边距,并设置盒模型为 border-box
。body { background-color: #eee; }
:设置页面背景颜色为浅灰色。header { color: white; background-color: #bbb; text-align: center; padding: 1rem; margin-bottom: 1rem; }
:设置头部标题的样式,包括文字颜色、背景颜色、对齐方式和内边距。.container { margin: auto; margin-top: 5rem; width: 600px; display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
:使用网格布局将输入和输出区域分为两列。.input, .output { background-color: white; padding: 1rem; border: 1px solid #bbb; position: relative; }
:设置输入和输出区域的背景颜色、内边距、边框和定位方式。textarea { resize: none; padding: 0.5rem; width: 250px; height: 150px; font-size: 1.1rem; }
:设置文本框的样式,包括禁止调整大小、内边距、宽度、高度和字体大小。.input .prompt { position: absolute; bottom: 1.6rem; left: 1.25rem; color: rgba(208, 2, 27, 0.9); font-size: 0.9rem; }
:设置提示信息的位置、颜色和字体大小。.prompt img { width: 30px; height: 30px; }
和 .output img { position: absolute; width: 250px; height: 150px; background-color: white; transform: translateX(-50%); left: 50%; }
:设置图片的宽度、高度和位置。// 将用户输入的带分隔符的 isbn 字符串转换只有纯数字和大写 X 字母的字符串
// 入参 str 为转换为包含任意字符的字符串
function getNumbers(str) {
// TODO: 待补充代码
return str.replace(/[^\dX]/g,'')
}
// 验证当前 ISBN10 字符串是否有效
// 入参 str 为待判断的只有纯数字和大写 X 字母的字符串
/**
*
* @param {String} str
*/
function validISBN10(str) {
// TODO: 待补充代码
if(!/^\d{9}[\dX]$/.test(str)){
return false
}
let arr = str.slice(0,9).split('')
let sum = arr.map(Number).reduce((acc,cur,idx)=>{
return acc + cur*(idx+1)
},0)
let check = (sum%11 == 10 ? "X" : String(sum%11))
return check == str[str.length-1]
}
// 将用户输入的 ISBN-10 字符串转化为 ISBN-13 字符串
// 入参 isbn 为有效的 ISBN-10 字符串
function ISBN10To13(isbn) {
// TODO: 待补充代码
let str = '978'+isbn.slice(0,9)
let sum = str.split('').map(Number).reduce((acc,cur,idx)=>{
return acc + ((idx+1)%2==0?cur*3:cur)
},0)
let check = (sum%10==0?'0':String(10-sum%10))
return str + check
}
// 测试用例
console.log(getNumbers("7-5600-3879-4")); // 7560038794
console.log(getNumbers("7 5600 3879 4")); // 7560038794
console.log(validISBN10("7560038794")); // true
console.log(validISBN10("7560038793")); // false
console.log(validISBN10("756003879")); // false
console.log(validISBN10("756003879004")); // false
console.log(ISBN10To13("7560038794")); // 9787560038797
console.log(ISBN10To13("3598215088")); // 9783598215087
<代码功能概述>
这段 JavaScript 代码定义了三个函数,用于处理 ISBN 号码的转换和验证。
<详细解释>
getNumbers
函数:
/[^\dX]/g
过滤掉字符串中的非数字和非大写字母 X
的字符。validISBN10
函数:
/^\d{9}[\dX]$/
检查字符串是否符合 ISBN - 10 的格式。X
,否则为余数对应的数字。ISBN10To13
函数:
978
。0
,否则为 10 - 余数
。四、工作流程▶️
isbnNums
计算属性过滤掉用户输入中的分隔符。validISBN
计算属性判断输入的 ISBN - 10 是否有效。convertedISBN
计算属性根据输入的有效性将 ISBN - 10 转换为 ISBN - 13。validISBN
的值,显示不同的图标和提示信息。outputImage
方法。convertedISBN
存在,使用 JsBarcode
库生成条形码。