基于正则表达式的行删除脚本(JS)不起作用

Posted

技术标签:

【中文标题】基于正则表达式的行删除脚本(JS)不起作用【英文标题】:Regex-based line deletion script (JS) not working 【发布时间】: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+)*(\.\w2,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+)*(\.\w2,3)+$/ 容易发生灾难性的回溯。无论您在哪里找到此模式,都让他们知道它至少应该是 /^\w+([.-]\w+)*@\w+([.-]\w+)*(\.\w2,3)+$/ 如果显示没有这样的文件或目录,请检查文件的路径是否正确。此外,createReadStream 可能只允许您读取,而不是写入。 请provide your input file 以及您预期输出的示例。 另外,不确定这应该做什么: if(str && str.length === 3 && Number(str[1]) && str[1] ) 您是否要检查是否str[1] 是一个数字,还是将其转换为一个数字并检查它是否不为空或未定义? 请看看这些网站:TLD list; valid/invalid addresses; regex for RFC822 email address 【参考方案1】:

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

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

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

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

https://nodejs.org/api/fs.html https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Promise https://itnext.io/javascript-promises-with-node-js-e8ca827e0ea3

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

创建 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 库中的知识:)

【讨论】:

以上是关于基于正则表达式的行删除脚本(JS)不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 正则表达式不起作用[重复]

具有捕获组的有效正则表达式,但 sed 脚本不起作用

正则表达式否定后缀否定环视不起作用

Javascript 正则表达式逗号检测不起作用

使用 JS 正则表达式从 html 中删除所有脚本标签

shell脚本——正则表达式(包含grep详细介绍及应用)