Как перевести этот код Python на Node.js

Я получил здесь очень хороший ответ о том, как очистить строку/удалить строку в файле без необходимости обрезать файл или заменить файл новой версией файла, вот код Python:

#!/usr/bin/env python

import re,os,sys
logfile = sys.argv[1]
regex = sys.argv[2]

pattern = re.compile(regex)

with open(logfile,"r+") as f:
    while True:
        old_offset = f.tell()
        l = f.readline()
        if not l:
            break
        if pattern.search(l):
            # match: blank the line
            new_offset = f.tell()
            if old_offset > len(os.linesep):
                old_offset-=len(os.linesep)
            f.seek(old_offset)
            f.write(" "*(new_offset-old_offset-len(os.linesep)))

этот скрипт можно назвать так:

./clear-line.py <file> <pattern>

В образовательных целях я пытаюсь выяснить, смогу ли я написать это в Node.js. Я, конечно, могу прочитать файл с Node.js построчно. Но я не уверен, есть ли в Node.js эквивалентные вызовы для Tell/Seek в этом случае.

эквивалент для записи, безусловно,

https://nodejs.org/api/fs.html#fs_fs_write_fd_buffer_offset_length_position_callback

вот моя попытка

#!/usr/bin/env node

const readline = require('readline');
const fs = require('fs');

const file = process.argv[2];
const rgx = process.argv[3];

const fd = fs.openSync(file, 'r+');

const rl = readline.createInterface({
    input: fs.createReadStream(null, {fd: fd})
});

let position = 0;

const onLine = line => {

    position += line.length;

    if (String(line).match(rgx)) {

        let len = line.length;

        rl.close();
        rl.removeListener('line', onLine);

        // output the line that will be replaced/removed
        process.stdout.write(line);

        fs.write(fd, new Array(len + 1).join(' '), position, 'utf8', err => {
            if (err) {
                process.stderr.write(err.stack || err);
                process.exit(1);
            }
            else {
                process.exit(0);
            }

        });

    }

};

rl.on('line', onLine);

Это не совсем правильно - я не думаю, что правильно вычисляю смещение/положение. Возможно, кто-то, кто знает Python и Node, сможет мне помочь. Я не очень хорошо разбираюсь в вычислении позиции/смещения в файлах, особенно с точки зрения буферов.

Вот данные в текстовом файле, с которым я работаю. Все, что я хочу сделать, это прочитать первую непустую строку, а затем удалить эту строку из файла и записать ее в стандартный вывод.

Это могут быть любые данные без пробелов, но вот JSON, с которым я работаю:

{"dateCreated":"2016-12-26T09:52:03.250Z","pid":5371,"count":0,"uid":"7133d123-e6b8-4109-902b-7a90ade7c655","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.290Z","pid":5371,"count":1,"uid":"e881b0a9-8c28-42bb-8a9d-8109587777d0","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.390Z","pid":5371,"count":2,"uid":"065e51ff-14b8-4454-9ae5-b85152cfcb64","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.491Z","pid":5371,"count":3,"uid":"5af80a95-ff9d-4252-9c4e-0e421fd9320f","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.595Z","pid":5371,"count":4,"uid":"961e578f-288b-413c-b933-b791f833c037","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.696Z","pid":5371,"count":5,"uid":"a65cbf78-2ea1-4c3a-9beb-b4bf56e83a6b","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.799Z","pid":5371,"count":6,"uid":"d411e917-ad25-455f-9449-ae4d31c7b1ad","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.898Z","pid":5371,"count":7,"uid":"46f8841d-c86c-43f2-b440-8ab7feea7527","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:04.002Z","pid":5371,"count":8,"uid":"81b5ce7e-2f4d-4acb-884c-442c5ac4490f","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:04.101Z","pid":5371,"count":9,"uid":"120ff45d-74e7-464e-abd5-94c41e3cd089","isRead":false,"line":"foo bar baz"}

person Alexander Mills    schedule 26.12.2016    source источник


Ответы (2)


Вы должны учитывать символ новой строки в конце каждой строки, который не включен в «строку», которую вы получаете через модуль readline. То есть вы должны обновить позицию до position += (line.length + 1), а затем при записи просто использовать position (без -1).

person Omri Sivan    schedule 26.12.2016
comment
есть идеи, в чем может быть разница между байтами (прочитанными байтами) и позицией (как я ее вычислил)? В этом случае, кажется, работает, если я делаю позицию равной количеству символов в файле до точки. Но если я сделаю позицию равной количеству прочитанных байтов, это не сработает, и количество прочитанных байтов будет больше, чем количество символов. - person Alexander Mills; 26.12.2016
comment
Это просто другое представление количества данных: прочитанные байты — это количество байтов, которые используются для хранения этой строки, а позиция представляет количество символов в этой конкретной строке. Вы также можете прочитать этот файл напрямую через модуль fs узла и работать с байтами. Тем не менее, readline — это гораздо более удобный модуль более высокого уровня, с которым можно работать для ваших конкретных целей. - person Omri Sivan; 26.12.2016
comment
Также стоит отметить, что вы не можете полагаться на прочитанные байты с точки зрения позиционирования, если вы уже используете readline из-за того, как работают потоки — может случиться так, что весь поток был прочитан readline еще до того, как вы обработаете первая строка. - person Omri Sivan; 26.12.2016
comment
определенно согласен с этим утверждением - person Alexander Mills; 26.12.2016

Хорошо, я думаю, что понял, но если у кого-то есть говядина с этим, пожалуйста, не стесняйтесь критиковать. Это близко, но я думаю, что это нуждается в некоторой тонкой настройке, кажется, есть ошибка один за другим или что-то в этом роде.

#!/usr/bin/env node

const readline = require('readline');
const fs = require('fs');

const file = process.argv[2];
const rgx = new RegExp(process.argv[3]);

const fd = fs.openSync(file, 'r+');

const rl = readline.createInterface({
    input: fs.createReadStream(null, {fd: fd})
});

let position = 0;

const onLine = line => {

    if (String(line).match(rgx)) {

        let len = line.length;

        rl.close();
        rl.removeListener('line', onLine);

        // output the line that will be replaced/removed
        process.stdout.write(line + '\n');

        fs.write(fd, new Array(len + 1).join(' '), position, 'utf8',

            (err, written, string) => {

            if (err) {
                process.stderr.write(err.stack || err);
                return process.exit(1);
            }
            else {
                process.exit(0);
            }

        });

    }

   position += (line.length + 1);  // 1 is length of \n character

};

rl.on('line', onLine);
person Alexander Mills    schedule 26.12.2016
comment
Я как раз собирался опубликовать ответ, в котором упоминается fs.createReadStream... так как я думаю, что у вас есть правильная идея. Для эквивалента сообщения Python есть несколько способов приблизиться к нему (например, fs.readSync может работать). fs.ReadSteam имеет довольно много функций, с которыми вы можете работать, чтобы делать то, что вы пытаетесь сделать. - person l'L'l; 26.12.2016
comment
спасибо да, это близко к работе, но не совсем на 100% - person Alexander Mills; 26.12.2016
comment
Я не уверен, правильно ли я рассчитываю позицию. Я просто предполагаю, что position будет количеством символов в файле. - person Alexander Mills; 26.12.2016
comment
Это количество байтов, поэтому, если вы читаете Unicode, количество символов потенциально может варьироваться, поскольку не все они равны одному байту по длине. readStream.bytesRead также полезен, поскольку он отслеживает, сколько байтов было прочитано в потоке. - person l'L'l; 26.12.2016
comment
да, там не будет никаких символов юникода, я контролирую данные, которые идут в файл - person Alexander Mills; 26.12.2016