如何将此 Python 代码转换为 Node.js

Posted

技术标签:

【中文标题】如何将此 Python 代码转换为 Node.js【英文标题】:How to translate this Python code to Node.js 【发布时间】:2017-05-10 19:23:35 【问题描述】:

我在这里得到了一个很好的答案,关于如何清除文件中的一行/删除文件中的一行,而不必截断文件或用新版本的文件替换文件,这是 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 调用。

write 的等价物肯定是

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"

【问题讨论】:

【参考方案1】:

您应该考虑每行末尾的换行符,它不包含在您通过 readline 模块获得的“行”中。也就是说,你应该将位置更新为position += (line.length + 1),然后在写入时使用position(不带-1)。

【讨论】:

知道字节(读取的字节)和位置(我计算它的方式)之间可能有什么区别吗?在这种情况下,如果我使位置等于文件中直到该点的字符数,它似乎可以工作。但是,如果我使位置等于读取的字节数,它就不起作用,并且读取的字节数比字符数大一些,就会出现。 这只是数据量的不同表示 - 读取的字节数是用于存储此字符串的字节数,而位置表示此特定字符串中的字符数。您还可以通过节点的 fs 模块直接读取此文件,并按自己的方式处理字节。但是,readline 是一个更好、更高级别的模块,可用于您的特定目的。 还值得注意的是,如果您已经在使用 readline,则不能依赖于在定位方面读取的字节,因为流的工作方式 - 可能是整个流被读取的情况甚至在你处理第一行之前就读过。 绝对同意这个说法【参考方案2】:

好的,我想我明白了,但如果有人对此有任何意见,请随时批评。它很接近,但我认为它需要一些微调,似乎有一个错误或类似的错误。

#!/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);

【讨论】:

我正要发布一个提到 fs.createReadStream... 的答案,因为我认为您的想法是正确的。对于相当于 Python 的告诉,有几种方法可以接近它(例如,fs.readSync 可能有效)。 fs.ReadSteam 有很多功能可以用来做你想做的事情。 谢谢,它接近工作但不是 100% 我不确定我是否正确计算了位置。我只是假设位置将是文件中的字符数。 这是字节数,因此如果您正在阅读 unicode,“字符”的数量可能会有所不同,因为并非所有字符的长度都等于一个字节。 readStream.bytesRead 也很有用,因为它可以跟踪流中已读取的字节数。 是的,那里不会有任何 unicode 字符,但我控制文件中的数据

以上是关于如何将此 Python 代码转换为 Node.js的主要内容,如果未能解决你的问题,请参考以下文章

如何将此curl语句转换为python请求?

如何将此列表转换为 3xN 矩阵? Python

如何将此示例从 python2 转换为 python3

如何将此 linux 命令转换为 python 字符串? [复制]

如何将此 Curl 调用转换为 Python 3?

Node.js - 如何将流转换为字符串