JavaScript - чтение текстового файла с пробелами в массиве и использование в качестве таблицы поиска - PullRequest
2 голосов
/ 16 июня 2019

Прежде всего: я абсолютный новичок в JavaScript и начал 2 недели назад, чтобы учиться много часов в день. Я использую сервер node.JS в GNU / Linux, и я попробовал множество вариантов, чтобы достичь цели. К сожалению, я застрял и не знаю, как продолжить.

У меня есть текстовый файл с пробелами и переводами строк, и файл содержит около 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;
      });
    [...]

теперь я получаю массив с тремя объектами, но только последнее имя набора данных: снова отображается Берри

 [ { 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 / line-by-line совершенно неправильным, я должен вместо этого использовать 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);
    }

Переменная data - это typeof object, как только я начинаю использовать .split ('\ n'), и, следовательно, я не могу использовать мое следующее условие if. Это терпит неудачу, потому что это будет работать только на строке. Может быть, я указываю полностью в неправильном направлении, и это намного проще? Конечная цель: я хочу проверить строку поиска, такую ​​как «Apple» , по этой справочной таблице и получить соответствующие значения (имя, секунда, тер, b или любое из них).

Я действительно благодарен за любой полезный ответ или подсказку. Пожалуйста, будьте терпеливы со мной и честно сказали: я действительно много пробовал! Спасибо всем.

Ответы [ 2 ]

0 голосов
/ 16 июня 2019

Привет, Джордж, и пока большое спасибо.Я только перечитал ссылку, которую вы разместили, но позже углублюсь в нее.Без намерения предвидеть, я не думаю, что мой код потерпел неудачу, потому что я пытаюсь получить доступ к результату, прежде чем он там, как вы сказали.В варианте 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 и, следовательно, построчно обрабатывается, ему не нужнопетля.Действительно ли это была единственная линия, которая заставила меня заболеть и доставила неприятности?С другой стороны, я спрашиваю себя, как можно «украсить» код, чтобы сделать его более простым, поэтому мне не нужно писать каждое имя, sec, ter, wrd, a, b, c, spon column.Представьте себе, что у каждого есть 150 свойств на каждый объект, и было бы неприятно записать его в задницу.Вот почему я сначала попробовал простой arr.push (obj) , к сожалению, он не сработал, как я ожидал.

Любое полезное объяснение приветствуется.Еще раз спасибо!теперь мне нужно найти способ чтения / поиска по таблице поиска, которая хранится в памяти, чтобы я мог отобразить / вывести соответствующую пару ключей / значение, которое мне нужно.

0 голосов
/ 16 июня 2019

Прежде всего, добро пожаловать в 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)
...