使用Node.js解析文本文件街道地址并生成结构化对象数组
代码问题梳理
- 缺少地址行分组逻辑:每个地址对应2~3行文本(带单元号的地址占3行),原代码直接按单行遍历处理,没有把相关行聚合为同一个地址对象
line2函数完全错误:addressList是存储所有行的数组,不存在字符串的split方法,函数既没有入参也没有实际作用- 单元号匹配逻辑硬编码:仅固定匹配
Suite 42,无法适配其他单元号场景 - 缺少城市、州、邮编的拆分逻辑:原代码直接将整行赋值给state、zip字段,没有对「城市, 州 邮编」格式的行做解析
- 地址对象复用导致值覆盖:在循环外定义单个
address对象,每次修改都是覆盖同一个对象的属性,最终所有结果都会是最后一个地址的值 - 异步结果没有透出:使用readline异步读取文件,原代码既没有返回Promise也没有传入回调,外部调用无法获取处理后的结果
修正后可运行代码
const fs = require('fs'); const readline = require('readline'); const parseAddressFile = path => { return new Promise((resolve, reject) => { const rl = readline.createInterface({ input: fs.createReadStream(path), crlfDelay: Infinity }); const allLines = []; // 读取所有行并去除首尾空格、过滤空行 rl.on('line', line => { const trimmedLine = line.trim(); if (trimmedLine) allLines.push(trimmedLine); }); rl.on('close', () => { const result = []; const tempAddressLines = []; // 匹配城市、州、邮编行的正则规则:城市, 两个大写字母的州 5位邮编 const cityStateZipReg = /^(.+),\s*([A-Z]{2})\s*(\d{5})$/; for (const line of allLines) { const matchRes = line.match(cityStateZipReg); if (matchRes) { // 当前行是地址的结尾行,聚合前面暂存的行生成结构化地址 const [, city, state, zip] = matchRes; result.push({ address1: tempAddressLines[0], address2: tempAddressLines[1] || null, city, state, zip }); // 清空临时存储,准备处理下一个地址 tempAddressLines.length = 0; } else { // 是街道行或者单元号行,存入临时数组 tempAddressLines.push(line); } } resolve(result); }); rl.on('error', err => reject(err)); }); }; // 调用示例 // parseAddressFile('./address.txt').then(res => console.log(res)) module.exports = parseAddressFile;
实现逻辑说明
- 自动处理多余空格的边界场景:读取每行时自动去掉首尾空格,同时过滤空行
- 无需硬编码匹配单元号:通过正则识别地址结尾的「城市, 州 邮编」行,自动判断前面的行是街道还是单元号,适配2行/3行的地址格式
- 异步结果可正常获取:封装为Promise返回,外部可以直接用async/await或者then方法拿到结构化的地址数组
内容的提问来源于stack exchange,提问作者missbeauty
相关产品推荐
相关产品推荐

