繁体   English   中英

JavaScript-将空格分隔的文本文件读入数组并用作查找表

[英]JavaScript - reading a whitespace delimited text file into array and use as lookup table

首先,我是JavaScript的绝对入门者,从2周前开始每天学习很多小时。 我正在GNU / Linux上运行一个node.JS服务器,并且我尝试了许多变体来实现这一目标。 不幸的是我卡住了,不知道如何继续。

我有一个带有空格和换行符的文本文件,并且该文件包含有关> 2000行的内容。 我想将此文本文件读入我的javascript程序,以便以后用作查找表。 我不确定是否需要对它进行JSON字符串化以供以后使用,也许将其保留为对象/数组很简单,以后可以在我的查找函数中使用它。 我只想从此文本文件中提取包含字符“#”的行并将其用作定界符。 所有其他行都可以忽略。 每行代表一个数据集,元素,对象或任何被正确调用的东西。 最终目标是:用户要求输入“ Apple”,并且应该获得“ -9.99”和“ BTW”(例如)作为答案。 这是原始文本文件的示例:

 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();

这是代码输出的内容(请注意,我通过为每行输出添加时间戳来自定义控制台日志):

 2019-06-16 14:40:10 { name: 'Sugar',
 sec: '1051',
 ter: '331',
 wrd: 'BAD',
 a: '1.23',
 b: '-4.56',
 c: '-5.0',
 spon: 'WWF' }
 2019-06-16 14:40:10 { name: 'Apple',
 sec: '551',
 ter: '3815',
 wrd: 'F3W',
 a: '5.55',
 b: '-9.99',
 c: '-1.0',
 spon: 'BTW' }
 2019-06-16 14:40:10 { name: 'Berry',
 sec: '19',
 ter: '22',
 wrd: 'FF',
 a: '19.5',
 b: '-12.34',
 c: '5.0',
 spon: 'CYA' }

数据字段看起来不错,到目前为止文件已正确处理,但是=>对象“ 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对象,因此无法使用以下if子句。 它失败了,因为它仅适用于字符串。 也许我完全指出了错误的方向,这更简单了吗? 最终目标是:我想对照此查找表检查诸如“ Apple”之类的搜索字符串,并检索适当的值(名称,秒,ter,b或其中任何一个)。

非常感谢任何有用的答案或提示。 请对我耐心说老实话:我真的很努力! 谢谢大家。

首先,欢迎您来到SO,并赞扬您的重点和详尽问题。 做得好!

流解决方案无法按预期工作的原因是因为它是异步的,因此您尝试在结果真正出现之前对其进行访问。 查看我们的经典主题以了解更多信息。

但是,为了简单起见,我建议您坚持使用readFileSync解决方案。 一般来说,出于性能原因,不建议在node.js中使用同步功能,但鉴于文件很小(3000行),因此不会造成太大的伤害。

读取文件后,可以按以下方式完成解析:

 let text = fs.readFileSync('test.in', 'utf8'); let result = []; for (let line of text.trim().split('\\n')) { if (!line.includes('#')) continue; let s = line.trim().split(/[#\\s]+/g); result.push({ name: s[0], sec: s[1], ter: s[2], wrd: s[3], a: s[4], b: s[5], c: s[6], spon: s[7], }); } console.log(result) 

您好乔治,到目前为止,非常感谢。 我只是交叉阅读了您发布的链接,但稍后会深入探讨。 没有预期的意图,我认为我的代码不会失败,因为我正尝试在您所说的结果到来之前访问它。 在我发布的readline变体中,您看到我尝试了push函数将新对象添加到最初定义的数组中。

阅读您的代码并尝试后,我感到很好奇。 我对现成的代码不感兴趣,我不知道它的作用,但我真的很想了解幕后发生的事情以及一切工作原理。 这就是为什么我仍然问,我的目标是了解 因此,以我的拙见,您所做的事情与我之前尝试过的完全相同,唯一的区别是您的数组push命令看起来与我的不同。 我用了

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个属性,将其写下来会很麻烦。 这就是为什么我最初尝试一个简单的arr.push(obj)的原因 ,可惜它没有按我预期的那样工作。

任何有用的解释表示赞赏。 再次感谢你! 现在,我需要找到一种方法来读取/搜索存储在内存中的查找表,以便可以显示/输出所需的适当键对/值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM