JavaScript—将以空格分隔的文本文件读入数组并用作查找表
首先:我是JavaScript的绝对初学者,两周前开始每天学习很多小时。我在GNU/Linux上运行一个node.JS服务器,我尝试了很多变化来实现这个目标。不幸的是,我卡住了,不知道如何继续 我有一个带有空格和换行符的文本文件,该文件包含大约>2000行的内容。我想将这个文本文件读入我的javascript程序中,以便稍后用作查找表。我不确定是否需要将其JSON字符串化以供以后使用,也许将其作为一个对象/数组保留很简单,我可以在以后用于查找函数。我只想从这个文本文件中取出那些包含字符“#”的行,并将其用作分隔符。可以忽略所有其他行。每一行代表一个数据集、元素、对象或正确调用的任何内容。最终的目标是:用户要求“苹果”,他应该得到“-9.99”和“BTW”(例如)作为答案。以下是原始文本文件的示例:JavaScript—将以空格分隔的文本文件读入数组并用作查找表,javascript,file,parsing,text,filter,Javascript,File,Parsing,Text,Filter,首先:我是JavaScript的绝对初学者,两周前开始每天学习很多小时。我在GNU/Linux上运行一个node.JS服务器,我尝试了很多变化来实现这个目标。不幸的是,我卡住了,不知道如何继续 我有一个带有空格和换行符的文本文件,该文件包含大约>2000行的内容。我想将这个文本文件读入我的javascript程序中,以便稍后用作查找表。我不确定是否需要将其JSON字符串化以供以后使用,也许将其作为一个对象/数组保留很简单,我可以在以后用于查找函数。我只想从这个文本文件中取出那些包含字符“#”的行
Sugar# 1051# 331# BAD# 1.23# -4.56# -5.0# WWF#
N3T;
Apple# 551# 3815# F3W# 5.55# -9.99# -1.0# BTW#
BBC;
Berry# 19# 22# FF# 19.5# -12.34# 5.0# CYA#
T1K;
它应表示3个元素,每个元素包含8对:
name: 'Sugar'
sec: 1051
ter: 331
wrd: 'BAD'
a: 1.23
b: -4.56
c: -5.0
spon: 'WWF'
name: 'Apple'
sec: 551
ter: 3815
wrd: 'F3W'
a: 5.55
b: -9.99
c: -1.0
spon: 'BTW'
name: 'Berry'
sec: 19
ter: 22
wrd: 'FF'
a: 19.5
b: -12.34
c: 5.0
spon: 'CYA'
开始时,我尝试使用fs.readFileSync将整个文本文件作为字符串读取,但没有成功。失望的是,我尝试了另一种方法,readline逐行阅读我的文本文件,并进行过滤,因为我在网上得到的印象是,这种方法对内存更友好,甚至可以读取非常大的文件。虽然我很确定3000行是个笑话:)
这是我使用readline时的代码:
const fs = require('fs');
const readline = require('readline');
function readAndFilter (source, data) {
var fields;
var obj = new Object;
var arr = new Array;
const readAndFilter = readline.createInterface({
input: fs.createReadStream('test.in'),
crlfDelay: Infinity
});
readAndFilter.on('line', (line) => {
if ( line.match( /#/ ) ) {
fields = line.split( '#' ).slice();
obj.name = fields[0].trim();
obj.sec = fields[1].trim();
obj.ter = fields[2].trim();
obj.wrd = fields[3].trim();
obj.a = fields[4].trim();
obj.b = fields[5].trim();
obj.c = fields[6].trim();
obj.spon = fields[7].trim();
console.log(obj);
// let jsonView = JSON.stringify(obj);
// arr.push(obj);
}
});
readAndFilter.on('close', function() {
return arr;
});
}
readAndFilter();
这就是代码输出的内容(请注意,我通过为每行输出添加时间戳来定制控制台日志):
数据字段看起来不错,到目前为止文件处理正确,但是=>对象“obj”将只保存最后一个数据集(名称:Berry),因为它在每行之后都会被重写。我剪了线,仔细检查了一下
console.log(obj);
从readAndFilter.on('line'),…块中,将其插入到“close”块中:
[...]
readAndFilter.on('line', (line) => {
if ( line.match( /#/ ) ) {
fields = line.split( '#' ).slice();
obj.name = fields[0].trim();
obj.sec = fields[1].trim();
obj.ter = fields[2].trim();
obj.wrd = fields[3].trim();
obj.a = fields[4].trim();
obj.b = fields[5].trim();
obj.c = fields[6].trim();
obj.spon = fields[7].trim();
// let jsonView = JSON.stringify(obj);
// arr.push(obj);
}
});
readAndFilter.on('close', function() {
console.log(obj);
return arr;
});
[...]
产出为:
{ name: 'Berry',
sec: '19',
ter: '22',
wrd: 'FF',
a: '19.5',
b: '-12.34',
c: '5.0',
spon: 'CYA' }
这不能用作查找表,我需要数组中的所有行,以便稍后在查找例程中访问它们。因此,我尝试使用以下代码将每个对象添加到一个数组中:
[...]
readAndFilter.on('line', (line) => {
if ( line.match( /#/ ) ) {
fields = line.split( '#' ).slice();
obj.name = fields[0].trim();
obj.sec = fields[1].trim();
obj.ter = fields[2].trim();
obj.wrd = fields[3].trim();
obj.a = fields[4].trim();
obj.b = fields[5].trim();
obj.c = fields[6].trim();
obj.spon = fields[7].trim();
// let jsonView = JSON.stringify(obj);
arr.push(obj);
}
});
readAndFilter.on('close', function() {
console.log(arr);
return arr;
});
[...]
现在,我得到一个包含三个对象的数组,但只显示最后一个数据集名称:Berry
[ { name: 'Berry',
sec: '19',
ter: '22',
wrd: 'FF',
a: '19.5',
b: '-12.34',
c: '5.0',
spon: 'CYA' },
{ name: 'Berry',
sec: '19',
ter: '22',
wrd: 'FF',
a: '19.5',
b: '-12.34',
c: '5.0',
spon: 'CYA' },
{ name: 'Berry',
sec: '19',
ter: '22',
wrd: 'FF',
a: '19.5',
b: '-12.34',
c: '5.0',
spon: 'CYA' } ]
我甚至尝试了concat和许多其他变体。我到底做错了什么?我使用readline/逐行技术的方法完全错了吗?我应该改用fs.readFileSync吗?我也尝试过,下面是我使用fs.readFileSync的方法:
function readAndFilter () {
var fields;
var obj = new Object;
var arr = new Array;
var data = fs.readFileSync('test.in', 'utf8').replace(/\r\n/g,'\n').split('\n').filter(/./.test, /\#/)
/*
if ( data.match( /#/ ) ) {
fields = data.split( '#' ).slice();
obj.name = fields[0].trim();
obj.cqz = fields[1].trim();
obj.itu = fields[2].trim();
obj.cont = fields[3].trim();
obj.lng = fields[4].trim();
obj.lat = fields[5].trim();
obj.tz = fields[6].trim();
obj.pfx = fields[7].trim();
};
*/
console.log(typeof data + "\n" + data);
}
当我开始使用.split('\n')时,变量数据就是typeof object,因此我不能使用下面的if子句。它失败了,因为它只对字符串有效。也许我完全指向了错误的方向,而且更简单?最终目标是:我想检查像“Apple”这样的搜索字符串根据此查找表检索适当的值(名称、秒、秒、秒、秒或其中任何一个)
我真的很感谢任何有帮助的回答或提示。请耐心地对我说:我真的尝试了很多!谢谢大家。首先,欢迎来到SO,并对你的重点和详细的问题表示赞赏。干得好 您的流解决方案不能按预期工作的原因是它是异步的,因此您试图在结果实际存在之前访问它。请查看我们的以了解更多信息 然而,为了简单起见,我建议坚持使用
readFileSync
解决方案。一般来说,出于性能原因,node.js中不建议使用同步功能,但考虑到文件很小(3000行),它不会造成太大的伤害
读取文件后,可以按如下方式进行解析:
let text=fs.readFileSync('test.in','utf8');
让结果=[];
对于(让text.trim().split('\n')的行){
如果(!line.includes('#'))
继续;
设s=line.trim().split(/[\s]+/g);
结果:推({
名称:s[0],
第2节:s[1],
三:s[2],
wrd:s[3],
答:s[4],,
b:s[5],
c:s[6],
主办方:s[7],
});
}
console.log(结果)
你好,George,非常感谢。我只是交叉阅读了您发布的链接,但稍后将深入研究。我无意预料,我认为我的代码不会失败,因为我正在尝试访问结果,正如您所说的那样。在我发布的readline变体中,您可以看到我尝试了推送功能来添加新对象进入我在开始时定义的数组
阅读了你的代码后,我很好奇并尝试了它。我对一个随时可用的代码不感兴趣,因为我不知道它是做什么的,但我真的很想了解幕后发生了什么以及一切是如何工作的。这就是为什么我仍然在问,我的目标是了解。因此,在我看来,你做到了这和我以前试过的一样,唯一的区别是你的数组推送命令看起来和我的不同
arr.push(obj);
这显然失败了。如前所述,我对readline变量使用了以下代码:
[...]
readAndFilter.on('line', (line) => {
if ( line.match( /#/ ) ) {
fields = line.split( '#' ).slice();
obj.name = fields[0].trim();
obj.sec = fields[1].trim();
obj.ter = fields[2].trim();
obj.wrd = fields[3].trim();
obj.a = fields[4].trim();
obj.b = fields[5].trim();
obj.c = fields[6].trim();
obj.spon = fields[7].trim();
arr.push(obj);
}
});
readAndFilter.on('close', function() {
console.log(arr);
return arr;
});
[...]
因此,我刚刚更改/删除了提到的行“arr.push(obj)”,并替换了push功能,使其看起来与您的功能相同:
[...]
readAndFilter.on('line', (line) => {
if ( line.match( /#/ ) ) {
fields = line.split( '#' ).slice();
arr.push({
name: fields[0].trim(),
sec: fields[1].trim(),
ter: fields[2].trim(),
wrd: fields[3].trim(),
a: fields[4].trim(),
b: fields[5].trim(),
c: fields[6].trim(),
spon: fields[7].trim(),
});
}
});
readAndFilter.on('close', function() {
console.log(arr);
return arr;
});
[...]
通过这种方式,它输出与您的代码相同的结果,工作!!!*因为我使用readline,所以逐行处理,它不需要for循环。真的是这一行让我恶心并造成了麻烦吗?另一方面,我问自己如何“美化”它代码使它更简单,所以我不需要写每个名称,sec,ter,wrd,a,b,c,spon列。假设每个对象有150个属性,写下来会很痛苦。这就是我最初尝试simp的原因
[...]
readAndFilter.on('line', (line) => {
if ( line.match( /#/ ) ) {
fields = line.split( '#' ).slice();
arr.push({
name: fields[0].trim(),
sec: fields[1].trim(),
ter: fields[2].trim(),
wrd: fields[3].trim(),
a: fields[4].trim(),
b: fields[5].trim(),
c: fields[6].trim(),
spon: fields[7].trim(),
});
}
});
readAndFilter.on('close', function() {
console.log(arr);
return arr;
});
[...]