const BYTE_MIN = 0 const BYTE_MAX = 0xFF const CONTROL_LABELS = { 0x00: 'NUL', 0x01: 'SOH', 0x02: 'STX', 0x03: 'ETX', 0x04: 'EOT', 0x05: 'ENQ', 0x06: 'ACK', 0x07: 'BEL', 0x08: 'BS', 0x09: '\\t', 0x0A: '\\n', 0x0B: 'VT', 0x0C: '\\f', 0x0D: '\\r', 0x0E: 'SO', 0x0F: 'SI', 0x10: 'DLE', 0x11: 'DC1', 0x12: 'DC2', 0x13: 'DC3', 0x14: 'DC4', 0x15: 'NAK', 0x16: 'SYN', 0x17: 'ETB', 0x18: 'CAN', 0x19: 'EM', 0x1A: 'SUB', 0x1B: 'ESC', 0x1C: 'FS', 0x1D: 'GS', 0x1E: 'RS', 0x1F: 'US', 0x20: 'SP', 0x7F: 'DEL' } function formatHexByte(value) { return `0x${(Number(value) & BYTE_MAX).toString(16).toUpperCase().padStart(2, '0')}` } function getDefaultRows() { return [ { label: '字符', meta: '', value: '--', copyValue: '' }, { label: 'HEX', meta: '', value: '--', copyValue: '' }, { label: 'DEC', meta: '', value: '--', copyValue: '' } ] } function createEmptyResultState() { return { asciiCodeErrorText: '', asciiCodeResultRows: getDefaultRows() } } function splitValueTokens(text) { return String(text || '') .trim() .split(/[\s,;,;]+/) .map((token) => token.trim()) .filter(Boolean) } function tokenLooksNumeric(token) { return /^0x/i.test(token) || /^\d+$/.test(token) } function tokenIsValidNumeric(token) { return /^0x[0-9a-f]+$/i.test(token) || /^\d+$/.test(token) } function shouldParseAsNumeric(text) { const tokens = splitValueTokens(text) if (!tokens.length) return false return tokens.every(tokenLooksNumeric) } function parseNumericToken(token) { if (!tokenIsValidNumeric(token)) { throw new Error('数值格式无效') } const value = /^0x/i.test(token) ? parseInt(token.slice(2), 16) : Number(token) if (!Number.isInteger(value) || value < BYTE_MIN || value > BYTE_MAX) { throw new Error('数值范围需为 0 - 255') } return value } function parseNumericBytes(text) { return splitValueTokens(text).map(parseNumericToken) } function parseTextBytes(text) { const bytes = [] Array.from(String(text || '')).forEach((char) => { const value = char.codePointAt(0) if (!Number.isInteger(value) || value < BYTE_MIN || value > BYTE_MAX) { throw new Error('字符需在 0 - 255 范围内') } bytes.push(value) }) return bytes } function formatChar(value) { const byte = Number(value) & BYTE_MAX if (Object.prototype.hasOwnProperty.call(CONTROL_LABELS, byte)) return CONTROL_LABELS[byte] if (byte >= 0x21 && byte <= 0x7E) return String.fromCharCode(byte) return `\\x${byte.toString(16).toUpperCase().padStart(2, '0')}` } function formatDisplayText(bytes = []) { if (!bytes.length) return '--' if (bytes.every((byte) => { const value = Number(byte) & BYTE_MAX return value >= 0x21 && value <= 0x7E })) { return bytes.map((byte) => String.fromCharCode(Number(byte) & BYTE_MAX)).join('') } return bytes.map(formatChar).join(' ') } function bytesToText(bytes = []) { return bytes.map((byte) => String.fromCharCode(Number(byte) & BYTE_MAX)).join('') } function createResultRows(bytes = []) { if (!bytes.length) return getDefaultRows() const hexText = bytes.map(formatHexByte).join(' ') const decText = bytes.map((byte) => String(Number(byte) & BYTE_MAX)).join(' ') const charText = formatDisplayText(bytes) return [ { copyValue: bytesToText(bytes), label: '字符', value: charText }, { copyValue: hexText, label: 'HEX', value: hexText }, { copyValue: decText, label: 'DEC', value: decText } ] } function buildState(source = {}) { const inputText = String(source.asciiCodeInputText || '') const trimmedText = inputText.trim() if (!trimmedText) { return { asciiCodeInputText: inputText, ...createEmptyResultState() } } try { const numericMode = shouldParseAsNumeric(trimmedText) const bytes = numericMode ? parseNumericBytes(trimmedText) : parseTextBytes(inputText) return { asciiCodeErrorText: '', asciiCodeInputText: inputText, asciiCodeResultRows: createResultRows(bytes) } } catch (error) { return { asciiCodeErrorText: error && error.message ? error.message : '转换失败', asciiCodeInputText: inputText, asciiCodeResultRows: getDefaultRows() } } } function createInitialState() { return buildState({ asciiCodeInputText: '' }) } function updateState(state, changedData = {}) { return buildState({ ...state, ...changedData }) } function clearInput(state = {}) { return updateState(state, { asciiCodeInputText: '' }) } module.exports = { clearInput, createInitialState, formatHexByte, updateState }