【问题标题】:Regex-based line deletion script (JS) not working基于正则表达式的行删除脚本(JS)不起作用
【发布时间】:2020-03-23 19:58:27
【问题描述】:

我有一个脚本可以读取文件并通过模式比较字符串,如果它返回 false,它将删除 .txt 文件中的行。

这是我的代码

const readline = require('readline');
const lineReplace = require('line-replace')
const fs = require('fs');
const inputFileName = './outputfinal.txt';

const readInterface = readline.createInterface({
    input: fs.createReadStream(inputFileName),
});

let testResults = [];
readInterface.on('line', line => {
    testResult = test(line);
    console.log(`Test result (line #${testResults.length+1}): `, testResult);
    testResults.push({ input: line, testResult } );
    if (testResult == false){
        console.log(`Line #${testResults.length} will get deleted from this list`);
        lineReplace({
          file: './outputfinal.txt',
          line: testResults.length,
          text: '',
          addNewLine: false,
          callback: onReplace   
        });

        function onReplace({file, line, text, replacedText}) {

        };
    };
});

// You can do whatever with the test results here.
//readInterface.on('close', () => {
//    console.log("Test results:", testResults);
//});

function test(str){

    let regex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; // email regex

    str = str.split(","); 

    // string should be of length 3 with str[1] number of length 7
    if(str && str.length === 3 && Number(str[1]) && str[1] ) {

        let temp = str[0].split("-");

        // check for 85aecb80-ac00-40e3-813c-5ad62ee93f42 separately.
        if(temp && temp.length === 5 &&  /[a-zA-Z\d]{8}/.test(temp[0]) &&  /[a-zA-Z\d]{4}/.test(temp[1]) &&  /[a-zA-Z\d]{4}/.test(temp[2]) &&  /[a-zA-Z\d]{4}/.test(temp[3]) &&  /[a-zA-Z\d]{12}/.test(temp[4])){

            // email regex
            if(regex.test(str[2])) {
                return true;
            } else {
                return false;
            }
        } else { 
            return false
        }
    } else {
        return false;
    }
}

但不工作,返回错误没有这样的文件或目录,我不认为这是做一个 line remover 脚本的正确方法

【问题讨论】:

  • 仅供参考:/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/ 容易发生灾难性的回溯。无论您在哪里找到此模式,都让他们知道它至少应该是 /^\w+([.-]\w+)*@\w+([.-]\w+)*(\.\w{2,3})+$/
  • 如果显示没有这样的文件或目录,请检查文件的路径是否正确。此外,createReadStream 可能只允许您读取,而不是写入。
  • provide your input file 以及您预期输出的示例。
  • 另外,不确定这应该做什么: if(str && str.length === 3 && Number(str[1]) && str[1] ) 您是否要检查是否str[1] 是一个数字,还是将其转换为一个数字并检查它是否不为空或未定义?

标签: javascript node.js regex


【解决方案1】:

首先,如果错误是“没有这样的文件或目录”是因为该文件不存在。请首先检查该文件是否存在于您项目的同一根目录中。

其次,不要使用库“line-replace”,如果你检查代码这会创建一个 tmp 文件并用替换重写所有文件在一个 tmp 中。完成该过程后,tmp 文件将重命名为原始文件。

第三,如果您分析代码,“lineReplace”是异步的。因此有时会尝试同时打开多次文件,然后再次同时写入。这将产生意想不到的结果。

最好的建议是你必须了解 Nodejs 中 File 的工作原理和 Promises (async):

如果您看到下一个代码,您将看到接下来的步骤:

  • 创建 tmp 路由
  • 创建 tmp 文件
  • 创建一个承诺:
    • 创建readline接口
    • 使用 try catch 处理每一行以在出现错误时拒绝
    • 完成该过程后,将 tmp 文件替换为原始文件,使用 try-catch 以在出现错误时拒绝
  • 等待完成promise,如果出错删除tmp文件
const fs = require('fs');
const readline = require('readline');

async function replaceLineWithConditional(pathFile, conditional) {
    // tmpFile name
    const tmpFilePath = `${pathFile}.tmp`;

    // Create write stream
    const tmpStream = fs.createWriteStream(tmpFilePath);

    // Process it
    const processFile = new Promise((resolve, reject) => {
        const rl = readline.createInterface({
            input: fs.createReadStream(pathFile),
        });

        // Process line
        rl.on("line", (input) => {
            try {
                if (conditional(input)) {
                    tmpStream.write(input); // input
                    tmpStream.write("\n"); // linejump
                }
            } catch (err) {
                // Reject error
                reject(err);
            }
        });

        // Finish
        rl.on("close", () => {
            try {
                // Move the tmpFile
                tmpStream.close();
                fs.renameSync(tmpFilePath, pathFile);

                // Resolve it
                resolve(true);
            } catch (err) {
                // Reject error
                reject(err);
            }
        });
    });

    try {
        // Await the promise
        return await processFile;
    } catch (err) {
        // Delete the tmp file and throw the error
        tmpStream.close();
        fs.unlinkSync(tmpFilePath);
        throw err;
    }
}

因此,您可以使用条件函数过程作为回调调用该函数。例如,我想保留所有长度超过 3 且不以“a”开头的行:

// async/await:
await replaceLineWithConditional("./test.txt", (line) => {
    return line.length > 3 && /^[^a]/.test(line);
});

// then/catch:
replaceLineWithConditional("./test.txt", (line) => {
    return line.length > 3 && /^[^a]/.test(line);
}).then(...).catch(...);

输入:

Hi
Hello
abcdef
a
lalalal

输出:

Hello
lalalal

如果您希望文件不要以结束行结束。 (注意:Why should text files end with a newline?)这可能是一个测验问题,以测试fs 库中的知识:)

【讨论】:

    猜你喜欢
    • 2015-08-25
    • 2017-11-24
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 2021-09-28
    相关资源
    最近更新 更多