-6

I have an script that reads the file and compares the string by a pattern, if it returns false it will delete the line on the .txt file.

This is my code

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;
    }
}

But isn't working, returns error no such file or directory, I dont think that is the correct way to do a line remover script

Tim P
  • 417
  • 6
  • 14
Monikhe
  • 35
  • 3
  • 3
    FYI: `/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/` is prone with catastrophic backtracking. Wherever you found this pattern, let them know it should be at least `/^\w+([.-]\w+)*@\w+([.-]\w+)*(\.\w{2,3})+$/` – Wiktor Stribiżew Nov 28 '19 at 08:03
  • If it says no such file or directory, check if the path to your file is correct. Also, createReadStream will probably only allow you to read, not write. – Glenn van Acker Dec 02 '19 at 11:50
  • Please [provide your input file](https://stackoverflow.com/help/how-to-ask) as well as an example of your expected output. – Tim Dec 02 '19 at 17:00
  • also, not sure what this is supposed to do: if(str && str.length === 3 && Number(str[1]) && str[1] ) Are you trying to check if str[1] is a number, or casting it to a number and checking if it is not null or undefined? – Glenn van Acker Dec 03 '19 at 08:33
  • Please, have a look at these sites: [TLD list](https://www.iana.org/domains/root/db); [valid/invalid addresses](https://en.wikipedia.org/wiki/Email_address#Examples); [regex for RFC822 email address](http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html) – Toto Dec 06 '19 at 14:34

1 Answers1

1

First, if the error is "no such file or directory" is because the file doesn't exist. Please check the file exists at first in the same root of your project.

Second, don't use the library "line-replace", if you check the code this create a tmp file and rewrite all the file in a tmp with the replacement. When finish the process the tmp file is renamed to the original.

Third, if you analyze the code the "lineReplace" is async. So there will sometimes to try to open multiple times the file at the same time and consequently write it at same time again. This will create an unsuspected result.

The best recommendation is you must see how File works and Promises (async) in nodejs:

If you see the next code, you will see the next steps:

  • Create the tmp Route
  • Create the tmp File
  • Create a promise:
    • Create a readline interface
    • Process each line with a try catch to reject in case of error
    • When finish the process replace the tmp file to original file with a try-catch to reject in case of error
  • Wait to finish the promise, in case of error delete the tmp file
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;
    }
}

So you could call the function with your conditional function process as a callback. For example, I want to keep it all the lines who have a length more than 3 and not start with "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(...);

input:

Hi
Hello
abcdef
a
lalalal

output:

Hello
lalalal

If you want the file don't finish with the end line. (take a note: Why should text files end with a newline?) this can be a Quiz problem to test knowledge in the fs library :)

jtwalters
  • 1,024
  • 7
  • 25