前言
在本文中,我们将探讨如何使用 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));