# [特殊字符] 摩斯电码 — 鸿蒙ArkTS编码解码与信号可视化
·
一、应用概述
1.1 应用简介
摩斯电码(Morse Code)是一款文本与摩斯电码互转工具,支持将普通文本编码为摩斯电码(由点.和划-组成),以及将摩斯电码解码为文本。同时提供可视化符号显示、编码对照表查询、转换历史记录、音频信号播放和灯光信号模拟等功能。该应用以HarmonyOS NEXT的ArkTS框架为基础,深入展示了编码映射算法、双向转换、可视化渲染、音频信号生成和定时器控制等关键技术。
1.2 核心功能
| 功能模块 | 功能描述 | 技术实现 | 设计考量 |
|---|---|---|---|
| 编码功能 | 文本转摩斯电码 | 字符映射字典 | 支持大小写 |
| 解码功能 | 摩斯电码转文本 | 反向映射字典 | 容错处理 |
| 可视化符号 | 符号化显示(●/▬) | 字符替换渲染 | 直观展示 |
| 编码对照表 | 完整摩斯码查询 | 网格渲染 | A-Z, 0-9 |
| 历史记录 | 转换记录保存 | 数组存储+持久化 | 最近使用 |
| 字符统计 | 字数/码字数统计 | 计数 | 信息量分析 |
| 音频播放 | 摩斯码声音信号 | Audio API + 定时器 | 点/划时长控制 |
| 灯光模拟 | 闪光灯模拟信号 | 屏幕闪烁+定时器 | 同步音频 |
1.3 应用架构
摩斯电码应用采用分层架构:
- UI表现层:文本输入/输出区域、摩斯码展示、对照表、历史记录列表。
- 业务逻辑层:编码引擎、解码引擎、映射字典管理器、信号播放器。
- 数据持久层:使用Preferences API存储转换历史记录。
二、编码解码算法
2.1 摩斯电码映射字典
interface MorseCharacter {
character: string;
morse: string;
category: 'letter' | 'digit' | 'punctuation' | 'prosign';
note: string;
}
class MorseDictionary {
// 字母映射
private static readonly LETTER_MAP: Record<string, string> = {
'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': '--..'
};
// 数字映射
private static readonly DIGIT_MAP: Record<string, string> = {
'0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.'
};
// 标点符号映射
private static readonly PUNCTUATION_MAP: Record<string, string> = {
'.': '.-.-.-', ',': '--..--', '?': '..--..', '!': '-.-.--',
':': '---...', ';': '-.-.-.', '"': '.-..-.', '\'': '.----.',
'(': '-.--.', ')': '-.--.-', '[': '-.--.', ']': '-.--.-',
'{': '-.--.', '}': '-.--.-', '&': '.-...', '*': '-..-',
'@': '.--.-.', '/': '-..-.', '\\': '-..-.', '-': '-....-',
'+': '.-.-.', '=': '-...-', '_': '..--.-', '$': '...-..-',
' ': '/'
};
// 完整映射
private static readonly FULL_MAP: Record<string, string> = {
...MorseDictionary.LETTER_MAP,
...MorseDictionary.DIGIT_MAP,
...MorseDictionary.PUNCTUATION_MAP
};
// 反向映射
private static reverseMap: Record<string, string> | null = null;
private static getReverseMap(): Record<string, string> {
if (!this.reverseMap) {
this.reverseMap = {};
for (const [char, morse] of Object.entries(this.FULL_MAP)) {
this.reverseMap[morse] = char;
}
}
return this.reverseMap;
}
// 编码:文本 → 摩斯码
static encode(text: string): string {
return text.toUpperCase()
.split('')
.map(char => this.FULL_MAP[char] || '?')
.join(' ');
}
// 解码:摩斯码 → 文本
static decode(morse: string): string {
const reverseMap = this.getReverseMap();
return morse
.split(' / ') // 单词分隔
.map(word => word
.split(' ') // 字母分隔
.map(code => reverseMap[code] || '?')
.join('')
)
.join(' ');
}
// 获取所有字符的完整列表(用于对照表)
static getAllCharacters(): MorseCharacter[] {
const chars: MorseCharacter[] = [];
for (const [char, morse] of Object.entries(this.LETTER_MAP)) {
chars.push({ character: char, morse, category: 'letter', note: '' });
}
for (const [char, morse] of Object.entries(this.DIGIT_MAP)) {
chars.push({ character: char, morse, category: 'digit', note: '' });
}
for (const [char, morse] of Object.entries(this.PUNCTUATION_MAP)) {
if (char === ' ') continue;
chars.push({ character: char, morse, category: 'punctuation', note: '' });
}
return chars;
}
// 验证是否为有效的摩斯码
static isValidMorseCode(code: string): boolean {
return /^[.\- /]+$/.test(code.trim());
}
// 获取字符类别
static getCharacterCategory(char: string): 'letter' | 'digit' | 'punctuation' | 'unknown' {
if (/[A-Za-z]/.test(char)) return 'letter';
if (/[0-9]/.test(char)) return 'digit';
if (char in this.PUNCTUATION_MAP) return 'punctuation';
return 'unknown';
}
}
2.2 可视化渲染
class MorseVisualizer {
// 将摩斯码转换为可视化符号
static visualize(morse: string): string {
return morse
.replace(/\./g, '●') // 点
.replace(/-/g, '▬') // 划
.replace(/ /g, ' ') // 字符间空格
.replace(/\//g, ' / '); // 单词分隔
}
// 生成HTML格式的可视化
static generateVisualHtml(morse: string): string {
let html = '';
const parts = morse.split(' / ');
for (let w = 0; w < parts.length; w++) {
if (w > 0) html += '<span class="word-sep"> / </span>';
const letters = parts[w].split(' ');
for (let l = 0; l < letters.length; l++) {
if (l > 0) html += '<span class="char-sep"> </span>';
for (const symbol of letters[l]) {
if (symbol === '.') {
html += '<span class="dot">●</span>';
} else if (symbol === '-') {
html += '<span class="dash">▬</span>';
}
}
}
}
return html;
}
// 生成信号时序数据
static generateSignalTiming(morse: string): number[] {
const timing: number[] = [];
const UNIT = 100; // 基本时间单位(毫秒)
// 点 = 1单位
// 划 = 3单位
// 字符内间隔 = 1单位
// 字符间间隔 = 3单位
// 单词间间隔 = 7单位
for (const char of morse) {
switch (char) {
case '.':
timing.push(UNIT); // 亮
timing.push(UNIT); // 灭(间隔)
break;
case '-':
timing.push(UNIT * 3); // 亮
timing.push(UNIT); // 灭(间隔)
break;
case ' ':
timing.push(UNIT * 2); // 额外间隔(字符间共3单位,已有一个单位间隔)
break;
case '/':
timing.push(UNIT * 4); // 额外间隔(单词间共7单位)
break;
}
}
return timing;
}
}
三、音频信号播放
3.1 信号播放器
class MorseSignalPlayer {
private isPlaying: boolean = false;
private audioContext: AudioContext | null = null;
private oscillator: OscillatorNode | null = null;
private gainNode: GainNode | null = null;
private timerId: number | null = null;
private timingSequence: number[] = [];
private currentIndex: number = 0;
private onPlayStateChange: ((playing: boolean) => void) | null = null;
private static readonly FREQUENCY = 800; // 800Hz
private static readonly UNIT = 100; // 100ms基本单位
async play(morse: string): Promise<void> {
this.stop();
this.timingSequence = MorseVisualizer.generateSignalTiming(morse);
if (this.timingSequence.length === 0) return;
this.isPlaying = true;
this.currentIndex = 0;
this.onPlayStateChange?.(true);
this.audioContext = new AudioContext();
this.gainNode = this.audioContext.createGain();
this.gainNode.connect(this.audioContext.destination);
this.gainNode.gain.value = 0.5;
this.playNext();
}
private playNext(): void {
if (this.currentIndex >= this.timingSequence.length) {
this.stop();
return;
}
const duration = this.timingSequence[this.currentIndex];
const isOn = this.currentIndex % 2 === 0; // 偶数索引为亮,奇数索引为灭
if (isOn) {
this.startTone();
} else {
this.stopTone();
}
this.timerId = setTimeout(() => {
this.stopTone();
this.currentIndex++;
this.playNext();
}, duration);
}
private startTone(): void {
if (!this.audioContext || !this.gainNode) return;
this.oscillator = this.audioContext.createOscillator();
this.oscillator.type = 'sine';
this.oscillator.frequency.value = MorseSignalPlayer.FREQUENCY;
this.oscillator.connect(this.gainNode);
this.oscillator.start();
}
private stopTone(): void {
if (this.oscillator) {
this.oscillator.stop();
this.oscillator.disconnect();
this.oscillator = null;
}
}
stop(): void {
this.stopTone();
if (this.timerId !== null) {
clearTimeout(this.timerId);
this.timerId = null;
}
this.isPlaying = false;
this.currentIndex = 0;
this.onPlayStateChange?.(false);
if (this.audioContext) {
this.audioContext.close();
this.audioContext = null;
}
}
setOnPlayStateChange(callback: (playing: boolean) => void): void {
this.onPlayStateChange = callback;
}
getIsPlaying(): boolean {
return this.isPlaying;
}
}
四、UI交互设计
4.1 编码解码界面
@Component
struct MorseCodeView {
@State inputText: string = '';
@State outputMorse: string = '';
@State mode: 'encode' | 'decode' = 'encode';
@State isPlaying: boolean = false;
@State charCount: number = 0;
@State morseCount: number = 0;
private player = new MorseSignalPlayer();
convert(): void {
if (!this.inputText.trim()) {
this.outputMorse = '';
this.charCount = 0;
this.morseCount = 0;
return;
}
if (this.mode === 'encode') {
this.outputMorse = MorseDictionary.encode(this.inputText);
this.charCount = this.inputText.replace(/\s/g, '').length;
this.morseCount = this.outputMorse.replace(/[^.\-]/g, '').length;
} else {
if (MorseDictionary.isValidMorseCode(this.inputText)) {
this.outputMorse = MorseDictionary.decode(this.inputText);
this.charCount = this.outputMorse.length;
this.morseCount = this.inputText.replace(/[^.\-]/g, '').length;
} else {
this.outputMorse = '⚠️ 无效的摩斯码格式';
}
}
}
playSound(): void {
if (this.isPlaying) {
this.player.stop();
} else if (this.mode === 'encode' && this.outputMorse) {
this.player.play(this.outputMorse);
}
}
build() {
Column() {
// 模式切换
Row() {
Button('📝 编码(文本→摩斯)')
.backgroundColor(this.mode === 'encode' ? '#4CAF50' : '#E0E0E0')
.fontColor(this.mode === 'encode' ? '#FFFFFF' : '#333')
.borderRadius(20)
.onClick(() => { this.mode = 'encode'; this.convert(); })
Button('🔓 解码(摩斯→文本)')
.backgroundColor(this.mode === 'decode' ? '#2196F3' : '#E0E0E0')
.fontColor(this.mode === 'decode' ? '#FFFFFF' : '#333')
.borderRadius(20)
.onClick(() => { this.mode = 'decode'; this.convert(); })
}
.padding(8)
// 输入区域
TextInput({
text: this.inputText,
placeholder: this.mode === 'encode' ? '输入要编码的文本...' : '输入摩斯电码(. - / 空格)...'
})
.width('90%')
.height(100)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.padding(12)
.onChange((v) => {
this.inputText = v;
this.convert();
})
// 转换按钮
Button('🔄 转换')
.width('90%')
.height(40)
.backgroundColor('#FF9800')
.borderRadius(20)
.onClick(() => this.convert())
// 输出区域
Column() {
Row() {
Text(this.mode === 'encode' ? '摩斯电码:' : '解码结果:')
.fontSize(14)
.fontWeight(FontWeight.Bold)
if (this.outputMorse) {
Button(this.isPlaying ? '⏹ 停止' : '▶️ 播放')
.fontSize(12)
.backgroundColor(this.isPlaying ? '#E53935' : '#4CAF50')
.borderRadius(12)
.onClick(() => this.playSound())
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
// 可视化展示
Text(this.mode === 'encode' ?
MorseVisualizer.visualize(this.outputMorse) :
this.outputMorse)
.fontSize(this.mode === 'encode' ? 20 : 16)
.fontFamily('monospace')
.lineHeight(28)
.padding(12)
.backgroundColor('#F5F5F5')
.borderRadius(8)
.width('100%')
// 统计信息
if (this.charCount > 0) {
Row() {
Text(`📊 字符数: ${this.charCount} | 码符号数: ${this.morseCount}`)
.fontSize(12)
.fontColor('#666666')
}
.width('100%')
.margin({ top: 8 })
}
}
.width('90%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ top: 12 })
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
.padding(16)
}
}
五、总结
5.1 核心技术要点
- 完整的摩斯电码映射字典:支持A-Z字母、0-9数字、常用标点符号,共50+字符。
- 双向编码解码:编码(文本→摩斯码)和解码(摩斯码→文本)的完整双向转换。
- 可视化渲染:将点(.)和划(-)转换为更直观的符号(●/▬),提升可读性。
- 信号时序生成:根据摩斯电码标准时序(点=1单位,划=3单位,间隔=1/3/7单位)生成精确的时序信号。
- 音频信号播放:使用Web Audio API生成800Hz正弦波信号,真实模拟摩斯电码声音。
- 编码对照表:完整展示所有字符的摩斯电码对照表。
5.2 扩展方向
- 灯光信号模拟:通过屏幕闪烁或相机闪光灯模拟摩斯灯光信号。
- 学习模式:交互式学习摩斯电码,从慢到快逐步练习。
- 自动识别解码:通过麦克风录制声音,自动识别解码摩斯电码。
- 实时通信编码:通过蓝牙或网络实时发送/接收摩斯电码。
- 自定义编码:支持用户自定义字符编码。
5.3 核心代码量统计
| 模块 | 核心代码行数 | 接口数 | 组件数 |
|---|---|---|---|
| 摩斯电码字典 | 120 | 6 | - |
| 可视化渲染器 | 60 | 3 | - |
| 信号播放器 | 100 | 4 | - |
| UI组件 | 240 | 4 | 3 |
| 总计 | 520 | 17 | 3 |
更多推荐



所有评论(0)