前言
在本文中,我们将探讨如何使用 JavaScript 编写一个简单的摩斯电码转换工具。这个工具能够将普通文本转换为摩斯电码,并且能够将摩斯电码转换回普通文本。[本文含有人工智能生成部分]
0x01 基础设置
首先,我们需要确保我们的代码能够运行在不同的环境中,包括那些可能缺少某些现代 JavaScript 特性的旧版浏览器。为此,我们定义了一个utils对象,它包含了一些用于检测数组和字符串处理的实用方法。
-
isArray方法:utils.isArray = function (value) { return Object.prototype.toString.apply(value) === "[object Array]"; };这个方法利用了
Object.prototype.toString的特性来检测传入的value是否为数组。toString方法会返回一个表示该对象的字符串,对于数组来说,这个字符串是"[object Array]"。 -
trim方法:utils.trim = function (value) { return value.trim ? value.trim() : value.replace(/^\s+|\s+$|/g, ""); };这个方法用于去除字符串两端的空白字符。如果浏览器支持
String.prototype.trim方法,则直接调用它;否则,使用正则表达式手动去除空白字符。
0x02 兼容性处理
为了确保代码在所有浏览器中都能正常工作,我们还需要处理控制台(console)对象可能不存在的情况,尤其是在某些旧版 IE 浏览器中。因此,我们添加了对 console.log 和 console.error 的默认定义。
console对象:
这段代码确保即使在没有var console = console || {}; console.log = console.log || function () {}; console.error = console.error || function () {};console对象或console.log和console.error方法的环境中,程序也不会抛出错误。如果这些方法不存在,它们将被定义为空函数。
0x03 字典类实现
接下来,我们创建了一个名为 Dictionary 的类,用于存储摩斯电码与普通字符之间的映射关系。该类提供了添加映射、反转映射和显示所有映射的功能。
-
构造函数:
function Dictionary() { this.datasource = {}; // 存储正向映射 this.rdatasource = {}; // 存储反向映射 } -
add方法:Dictionary.prototype.add = function (keys, values) { if (typeof keys === "undefined" || typeof values === "undefined") { console.error("Illegal arguments"); return; } if (utils.isArray(keys) && utils.isArray(values)) { if (keys.length != values.length) { console.error("keys length not equals values length"); return; } for (var i = 0; i < keys.length; i++) { this.datasource[keys[i]] = values[i]; } return; } this.datasource[keys] = values; };这个方法用于向字典中添加键值对。它可以接受单个键值对或两个数组作为参数。如果传入的是数组,它们的长度必须相同,否则会抛出错误。
-
reversal方法:Dictionary.prototype.reversal = function () { var tempData = this.datasource; for (var i in tempData) { if (tempData.hasOwnProperty(i)) { this.rdatasource[tempData[i]] = i; } } };这个方法用于生成反向映射,即将
datasource中的值作为键,键作为值存入rdatasource。 -
showAll方法:Dictionary.prototype.showAll = function (values) { var count = 0; console.log("-----------morse code mapping-----------"); for (var i in values) { if (values.hasOwnProperty(i)) { count++; console.log(i + "\t > " + values[i]); } } console.log("total count: " + count); };这个方法用于显示字典中的所有映射关系及其总数。
0x04 摩斯电码库
最后,我们构建了一个名为 morse 的对象,它是整个摩斯电码转换工具的核心。morse 对象包含了两个主要的方法:parse 和 decode。parse 方法负责将普通文本转换为摩斯电码,而 decode 方法则负责将摩斯电码转换回普通文本。
-
初始化:
var morse = (function (global) { var mcode = {}, r_special = /\<\w+\>/g, r_find = /^\<(\w+)\>$/; mcode.mdatas = (function () { var dictionaryDS = new Dictionary(); dictionaryDS.add( // 字母 [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ], [ ".", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", ], // 数字 ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], [ ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", "-----", ], // 特殊字符 ["AA", "AR", "AS", "BK", "BT", "CT", "SK", "SOS"], [".", "-.-", ".-...", "-...-", "-...-", "-.-.-", "...-.-", "...---..."], // 标点符号 [ ".", ":", ",", ";", "?", "=", "'", "/", "!", "-", "_", '"', "(", ")", "$", "&", "@", "+", ], [ ".", "-.-", ".-...", "-...-", "-.-.-", "..--..", "-...-", ".----.", "-..-.", "-.-.--", "-....-", "..--.-", ".-..-.", "-.--.", "-.--.-", "...-..-", ".-...", ".--.-.", ".-.-.", ] ); return dictionaryDS; })(); mcode.error_flag = false; mcode.parse = function (values) { console.log("input: " + values); mcode.error_flag = false; var _datasource = mcode.mdatas.datasource, item = "", a_special = [], a_temp = [], a_value = [], count = 0, result = ""; values = values.toUpperCase(); a_special = values.match(r_special); a_temp = values.split(r_special); for (var i = 0; i < a_temp.length; i++) { item = a_temp[i]; if (item !== "") { if (!item[0]) { item = item.split(""); } for (var j = 0; j < item.length; j++) { a_value[count++] = item[j]; } } if (i !== a_temp.length - 1) { a_value[count++] = a_special[i].match(r_find)[1]; } } for (var i = 0; i < a_value.length; i++) { item = a_value[i]; if (item === " ") { result += "/ "; } else if (typeof _datasource[item] === "undefined") { mcode.error_flag = true; console.error("Invalid characters in input."); result += "? "; } else { result += _datasource[item] + " "; } } return utils.trim(result); }; mcode.decode = function (values) { console.log("input: " + values); mcode.error_flag = false; mcode.mdatas.reversal(); var _rdatasource = mcode.mdatas.rdatasource, a_input = values.split(" "), result = "", item = "", c_result = ""; for (var i = 0; i < a_input.length; i++) { item = a_input[i]; if (item === "/") { result += " "; } else { c_result = _rdatasource[item]; if (typeof c_result === "undefined") { mcode.error_flag = true; console.error("Invalid characters in input."); result += "?"; } else { if (c_result.length > 1) { result += "<" + c_result + ">"; } else { result += c_result; } } } } return result; }; return mcode; })(this); -
parse方法:- 将输入字符串转换为大写。
- 使用正则表达式提取特殊字符(如
<AS>)。 - 将输入字符串分割成多个部分,并将每个部分进一步拆分为字符。
- 遍历每个字符,将其转换为对应的摩斯电码。如果遇到空格,则在结果中添加
/分隔符。如果遇到无效字符,则记录错误并输出问号?。 - 最后,使用
utils.trim方法去除结果字符串两端的空白字符。
-
decode方法:- 调用
reversal方法生成反向映射。 - 将输入的摩斯电码字符串按空格分割成多个部分。
- 遍历每个部分,将其转换为对应的字符。如果遇到
/,则在结果中添加空格。如果遇到无效的摩斯电码,则记录错误并输出问号?。 - 如果转换后的字符长度大于 1,则将其包裹在
<和>中,以表示特殊字符。
- 调用
0x05 测试和集成
完成上述步骤后,您可以测试您的摩斯电码转换工具,确保其能够正确地将普通文本转换为摩斯电码,并且能够准确地将摩斯电码解码回原始文本。
-
编码示例:
console.log(morse.parse("HELLO WORLD")); // 输出 ".... . .-.. .-.. --- / .-- --- .-. .-.. -.." -
解码示例:
console.log(morse.decode(".... . .-.. .-.. --- / .-- --- .-. .-.. -..")); // 输出 "HELLO WORLD"
0x06 总结
通过以上步骤,您已经了解了如何编写一个完整的摩斯电码转换工具。这个工具不仅能够处理普通的字母和数字,对如何处理跨浏览器兼容性问题也给出了解决方案,还能处理一些特殊的摩斯电码字符,并且具有良好的错误处理机制。希望这篇文章能帮助您更好地理解 JavaScript 编程的基础知识,并激发您探索更多有趣的项目。
0x07 完整代码
本代码编写于 2022 年,该部分仍可正常使用。
/*
* @author Pig2333
* @created 2022-01-20
*/
var utils = utils || {};
utils.isArray = function (value) {
return Object.prototype.toString.apply(value) === "[object Array]";
};
utils.trim = function (value) {
return value.trim ? value.trim() : value.replace(/^\s+|\s+$|/g, "");
};
// 解决 IE 不兼容 console 问题
var console = console || {};
console.log = console.log || function () {};
console.error = console.error || function () {};
// 使用字典存储摩斯码对照关系
function Dictionary() {
this.datasource = {};
this.rdatasource = {};
}
Dictionary.prototype.add = function (keys, values) {
if (typeof keys === "undefined" || typeof values === "undefined") {
console.error("Illegal arguments");
return;
}
if (utils.isArray(keys) && utils.isArray(values)) {
if (keys.length != values.length) {
console.error("keys length not equals values length");
return;
}
for (var i = 0; i < keys.length; i++) {
this.datasource[keys[i]] = values[i];
}
return;
}
this.datasource[keys] = values;
};
Dictionary.prototype.reversal = function () {
var tempData = this.datasource;
for (var i in tempData) {
if (tempData.hasOwnProperty(i)) {
this.rdatasource[tempData[i]] = i;
}
}
};
Dictionary.prototype.showAll = function (values) {
var count = 0;
console.log("-----------morse code mapping-----------");
for (var i in values) {
if (values.hasOwnProperty(i)) {
count++;
console.log(i + "\t > " + values[i]);
}
}
console.log("total count: " + count);
};
// morse code library
var morse = (function (global) {
var mcode = {},
r_special = /\<\w+\>/g,
r_find = /^\<(\w+)\>$/;
// store datas mapping
mcode.mdatas = (function () {
var dictionaryDS = new Dictionary();
// initial mappping
dictionaryDS.add(
[
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"AA",
"AR",
"AS",
"BK",
"BT",
"CT",
"SK",
"SOS",
".",
":",
",",
";",
"?",
"=",
"'",
"/",
"!",
"-",
"_",
'"',
"(",
")",
"$",
"&",
"@",
"+",
],
[
// letter
".-",
"-...",
"-.-.",
"-..",
".",
"..-.",
"--.",
"....",
"..",
".---",
"-.-",
".-..",
"--",
"-.",
"---",
".--.",
"--.-",
".-.",
"...",
"-",
"..-",
"...-",
".--",
"-..-",
"-.--",
"--..",
// number
".----",
"..---",
"...--",
"....-",
".....",
"-....",
"--...",
"---..",
"----.",
"-----",
// special charactor
".-.-",
".-.-.",
".-...",
"-...-.-",
"-...-",
"-.-.-",
"...-.-",
"...---...",
// punctuation
".-.-.-",
"---...",
"--..--",
"-.-.-.",
"..--..",
"-...-",
".----.",
"-..-.",
"-.-.--",
"-....-",
"..--.-",
".-..-.",
"-.--.",
"-.--.-",
"...-..-",
".-...",
".--.-.",
".-.-.",
]
);
return dictionaryDS;
})();
// error flag
mcode.error_flag = false;
// 将字符串转换为码
mcode.parse = function (values) {
console.log("input: " + values);
this.error_flag = false;
var _datasource = this.mdatas.datasource,
item = "",
a_special = [],
a_temp = [],
a_value = [],
count = 0,
result = "";
values = values.toUpperCase();
a_special = values.match(r_special);
a_temp = values.split(r_special);
// 将用户输入的字符串转换成数组
for (var i = 0; i < a_temp.length; i++) {
item = a_temp[i];
if (item !== "") {
// IE 无法通过下标来索引字符串
if (!item[0]) {
item = item.split("");
}
for (var j = 0; j < item.length; j++) {
a_value[count++] = item[j];
}
}
// 当前字符串为<AS>形式,提取 AS 字符
if (i !== a_temp.length - 1) {
a_value[count++] = a_special[i].match(r_find)[1];
}
}
// 将解析数组形式的用户输入值
for (var i = 0; i < a_value.length; i++) {
item = a_value[i];
if (item === " ") {
result += "/ ";
} else if (typeof _datasource[item] === "undefined") {
this.error_flag = true;
console.error("Invalid characters in input.");
result += "? ";
} else {
result += _datasource[item] + " ";
}
}
return utils.trim(result);
};
// 将码转换成字符串
mcode.decode = function (values) {
console.log("input: " + values);
this.error_flag = false;
this.mdatas.reversal();
var _rdatasource = this.mdatas.rdatasource,
a_input = values.split(" "),
result = "",
item = "",
c_result = "";
for (var i = 0; i < a_input.length; i++) {
item = a_input[i];
if (item === "/") {
result += " ";
} else {
c_result = _rdatasource[item];
if (typeof c_result === "undefined") {
this.error_flag = true;
console.error("Invalid characters in input.");
result += "?";
} else {
if (c_result.length > 1) {
result += "<" + c_result + ">";
} else {
result += c_result;
}
}
}
}
return result;
};
return mcode;
})(this);