i have this script, who i run in a program called discord bot maker. I'm trying to give the bot the possibility to search for a word in a txt file, then remove this word and save the file :
let fs = require('fs');
let a = tempVars('a');
let b = tempVars('carte');
fs.readFile(`resources/${a}.txt`, { encoding: 'utf-8' }, (err, data) => {
if (err) throw err;
let dataArray = data.split('\n'); // convert file data in an array
const searchKeyword = `${b}`; // we are looking for a line, contains, key word 'user1' in the file
const key = dataArray.filter((arr) => arr.includes(searchKeyword));
const index = key.length >= 1 && dataArray.indexOf(key[0]);
if (index > -1) dataArray.splice(index, 1);
// UPDATE FILE WITH NEW DATA
// IN CASE YOU WANT TO UPDATE THE CONTENT IN YOUR FILE
// THIS WILL REMOVE THE LINE CONTAINS 'user1' IN YOUR shuffle.txt FILE
const updatedData = dataArray.join('\n');
fs.writeFile(`resources/${a}.txt`, updatedData, (writeErr) => {
if (writeErr) throw err;
console.log('Successfully updated the file data');
});
});
the tempVars("xx") variables are given by a program named discord bot maker, so no trouble with that.
My problem is that when the var "b" (who is the parameter of a command in discord) doesnt exist in the txt file, the script delete the first word in the file !
How can i add a condition to this script (If b dont exist in file, stop the script and return a message)
thank you very mutch guys ! have a good day
You can use use replace method without converting file into arrays.
let fs = require('fs');
let a = tempVars('a');
let b = tempVars('carte');
fs.readFile(`resources/${a}.txt`, { encoding: 'utf-8' }, (err, data) => {
if (err) throw err;
const updatedData = data.replace(b, '');
fs.writeFile(`resources/${a}.txt`, updatedData, (writeErr) => {
if (writeErr) throw err;
console.log('Successfully updated the file data');
});
});
This method will replace only first matched word. In case, if you want to replace all matched word, as a first parameter, you can use Regular Expression.
Char g is stands for global, m is for multi-line.
const regex = new RegExp(b, 'gm')
data.replace(regex, '');
In case you want to test if the file contains requested word, you can use .includes function and if statement.
if (!data.includes(b)) {
console.log("Requested word is not present in file")
// Your logic here
return
}
Related
Say I have a file called test.txt which is fixed with nonsense text.
But among this text is a specific string containing numbers in single quotes ('') like so;
blahblahblah:
Blahblahblah:
targetNumber: '30' <== target numbers
Blahblahblah
How would I go about replacing only these single quoted numbers, without replacing the entire file contents like so;
blahblahblah:
Blahblahblah:
targetNumber: '22' <== changed numbers
Blahblahblah
So far the regex functions I've constructed using numerous other questions on StackOverflow don't seem want to work and if they do work, they don't work as expected because they always seem to replace the entire contents of the file rather than just that set of numbers.
My last regex attempt on this is below, but it doesn't work, it just replaces the entire file contents so I don't where I'm going wrong, I'm still learning regex currently, can anyone please help???
var folder = "just/a/test/folder";
fs.readFile(path.join(folder, 'test.txt'), 'utf8', (error, data) => {
if (error) {
console.log('Unable to Read File');
return;
};
var regex = /'\d{1,2}\'/
var str = data.substring(data.indexOf("targetNumber: ") + 14);
var m = str.match(regex)
var replace = str.replace(m[1], "22");
fs.writeFile(path.join(folder, 'test.txt'), replace, 'utf8', (error) => {
if (error) {
console.log('Modifying File failed')
return;
}
});
You should do the replacement over the data and then you can capture targetNumber: in a group, using that group again with $1 in the replacement followed by your replacement.
See the match and the replacement at this regex demo.
const folder = "just/a/test/folder";
const file = 'test.txt'
fs.readFile(path.join(folder, file), 'utf8', (error, data) => {
if (error) {
console.log('Unable to Read File');
return;
}
const regex = /\b(targetNumber:\s*')\d{1,2}'/g;
const replace = data.replace(regex, "$122'");
fs.writeFile(path.join(folder, file), replace, 'utf8', (error) => {
if (error) {
console.log('Modifying File failed')
}
});
});
I recently made a script in which I want to delete an EXACT match from a txt file with node. It print's out true but doesn't actually remove the line from the txt file. I am using discord to get the argument.
I'm not sure what I'm doing wrong but here is my script:
const fs = require('fs')
fs.readFile('notredeemed.txt', function (err, data) {
if (err) throw err;
if (data.toString().match(new RegExp(`^${args[0]}$`, "m"))) {
fs.readFile('notredeemed.txt', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data.replace(/${args[0]/g, '');
fs.writeFile('notredeemed.txt', result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
console.log("true")
If someone could help me I would appreciate it :)
I think you can do it very similarly as your current solution, just the regex is a little off.
Instead of just using ^ and $ to indicate that the entire string starts and ends with the args[0], I used two capture groups as the delimiters of a line.
This one matches any newline character or the beginning of the string. Works for first line of file, and prevents partial replacement e.g. llo replacing Hello:
(\n|^)
And this one matches a carriage return or the end of the string. This works for cases where there is no newline at the end of the file, and also prevents Hel replacing Hello:
(\r|$)
That should ensure that you are always taking out an entire line that matches your args.
I also eliminated the second readFile as it wasn't necessary to get it to work.
const fs = require("fs")
fs.readFile("notredeemed.txt", function (err, data) {
if (err) throw err
const match = new RegExp(`(\n|^)${args[0]}(\r|$)`)
const newFile = data.toString().replace(match, ``)
fs.writeFile("notredeemed.txt", newFile, "utf8", function (err) {
if (err) return console.log(err)
console.log("true")
})
})
Here is my solution.
Algorithm:
Split the file content into individual lines with your desired End of Line Flag (generally "\n" or "\r\n")
Filter all the lines that you want to delete
Join all the filtered lines back together with the EOL flag
const replacingLine = "- C/C++ addons with Node-API";
const fileContent = `- V8
- WASI
- C++ addons
- C/C++ addons with Node-API
- C++ embedder API
- C/C++ addons with Node-API
- Corepack`;
const newFileContent = replace({ fileContent, replacingLine });
console.log(newFileContent);
function replace({ fileContent, replacingLine, endOfLineFlag = "\n" }) {
return fileContent
.split(endOfLineFlag)
.filter((line) => line !== replacingLine)
.join(endOfLineFlag);
}
I am having an issue where I cannot seem to find a solution.
I have written a Discord bot from Discord.JS that needs to send a list of file names from a directory as one message. So far I have tried using fs.readddir with path.join and fs.readfilesync(). Below is one example.
const server = message.guild.id;
const serverpath = `./sounds/${server}`;
const fs = require('fs');
const path = require('path');
const directoryPath = path.join('/home/pi/Pablo', serverpath);
fs.readdir(directoryPath, function(err, files) {
if (err) {
return console.log('Unable to scan directory: ' + err);
}
files.forEach(function(file) {
message.channel.send(file);
});
});
Whilst this does send a message of every file within the directory, it sends each file as a separate message. This causes it to take a while due to Discord API rate limits. I want them to all be within the same message, separated with a line break, with a max of 2000 characters (max limit for Discord messages).
Can someone assist with this?
Thanks in advance.
Jake
I recommend using fs.readdirSync(), it will return an array of the file names in the given directory. Use Array#filter() to filter the files down to the ones that are JavaScript files (extentions ending in ".js"). To remove ".js" from the file names use Array#map() to replace each ".js" to "" (effectively removing it entirely) and use Array#join() to join them into a string and send.
const server = message.guild.id;
const serverpath = `./sounds/${server}`;
const { readdirSync } = require('fs');
const path = require('path');
const directoryPath = path.join('/home/pi/Pablo', serverpath);
const files = readdirSync(directoryPath)
.filter(fileName => fileName.endsWith('.js'))
.map(fileName => fileName.replace('.js', ''));
.join('\n');
message.channel.send(files);
Regarding handling the sending of a message greater than 2000 characters:
You can use the Util.splitMessage() method from Discord.JS and provide a maxLength option of 2000. As long as the number of chunks needed to send is not more than a few you should be fine from API ratelimits
const { Util } = require('discord.js');
// Defining "files"
const textChunks = Util.splitMessage(files, {
maxLength: 2000
});
textChunks.forEach(async chunk => {
await message.channel.send(chunk);
});
Built an array of strings (names of files) then join with "\n".
let names = []
fs.readdir(directoryPath, function(err, files) {
if (err) {
return console.log('Unable to scan directory: ' + err);
}
files.forEach(function(file) {
names << file
});
});
message.channel.send(names.join("\n"));
I'm trying to send temporary information to a json file where I can store them as an array of objects and then after some time, automatically reset the file back to an empty array.
The code reads fine at first and stores the information, but once it sets back to an empty array, the code no longer reads that it's empty and still does things when it shouldn't. When using the join command below it's supposed to check if it's empty and return if it is and not store anything until there is an enemy in there first. The response of "user joined the fight" still happens and nothing is stored in the array.
Here is the join command
const Discord = require('discord.js');
const fs = require('fs');
const enemySpawn = require('../EnemySpawn.json');
const { rpgbot } = require('../colors.json');
module.exports = {
name: 'join',
description: 'Used to join the grouping of players to fight an enemy that spawns',
execute(message, args) {
if (enemySpawn.length == 0) return message.channel.send('There\'s no enemy to fight!');
if (enemySpawn.some(user => user.id === message.author.id)) return message.channel.send('You already joined the current fight!');
// TODO add users stats
enemySpawn.push({
name: message.author.username,
id: message.author.id
})
fs.writeFile('./EnemySpawn.json', JSON.stringify(enemySpawn), err => {
if (err) console.error(err);
});
// TODO add current level of the user
const embed = new Discord.MessageEmbed()
.setColor(rpgbot)
.addField(`${message.author.username} joined the fight!`, '\u200B')
message.channel.send(embed);
},
};
Here is the function of getting the enemy and storing it first
const fs = require('fs');
const enemySpawn = require('./EnemySpawn.json');
const enemies = require('./Enemies.json')
getEnemy: function (message) {
if (!(enemySpawn.length == 0)) return;
let randomEnemy = enemies[Math.floor(Math.random() * enemies.length)];
enemySpawn.push({
enemy: randomEnemy.name,
health: randomEnemy.health
})
fs.writeFile('./EnemySpawn.json', JSON.stringify(enemySpawn), err => {
if (err) console.error(err);
});
message.channel.send(`Watch out! A ${randomEnemy.name} appeared!`);
}
And here is where it is called when someone sends a message which also has a timeout function to clear the array after 3 seconds for testing
const fs = require('fs');
const functions = require('./functions.js');
let used = false;
if (!used) {
functions.getEnemy(message);
used = true;
setTimeout(function () {
used = false;
fs.writeFile('./EnemySpawn.json', JSON.stringify([]), err => {
if (err) console.error(err);
});
}, 3000);
}
The only places I see you reading the json file is with this:
const enemySpawn = require('../EnemySpawn.json');
and both of those are in module initialization which will only ever be executed once at startup. So, after you write the empty array back to the file, you don't ever read it back again (unless you restart your server).
If you want that empty array to be read back in again, you have to actually read that JSON file again in real time during some operation.
I need a client to upload a text file. Then I want to parse the text file such that only lines with the word "object" in it is the only thing left in the text file. I have successfully coded the uploading part. But need help coding how to parse out the lines with "object" not in it. My node js code is below.
You can use the ReadLine API that's part of Node Core to iterate through the file line-by-line. You can use string.includes() to determine if your line contains the phrase you're looking for.
var readline = require('readline');
var fs = require('fs');
function filterFile(phrase, input) {
return Promise((resolve, reject) => {
var lines = [];
let rl = readline.createInterface({
input: input
});
rl.on('line', (line) => {
if (line.includes(phrase, 0))
lines.push(line);
});
rl.on('close', () => {
let filteredLines = Buffer.from(lines);
return resolve(fs.createReadStream(filteredLines));
});
rl.on('error', (err) => {
return reject(err);
});
});
}
Edit for Filtered Output Write Stream Example
We can take the resulting stream returned by filterFile() and pipe its contents into a new file like so
var saveDest = './filteredLines.txt');
filterFile('object', inputStream)
.then((filteredStream) => {
let ws = fs.createWriteStream(saveDest);
filteredStream.once('error', (err) => {
return Promise.reject(err);
});
filteredStream.once('end', () => {
console.log(`Filtered File has been created at ${saveDest}`);
return Promise.resolve();
});
filteredStream.pipe(ws);
});
Step : 1
Divide the line using --
var x='i am object\ni m object';
var arr = x.split('\n');
Step : 2
For each line, test with object regexp
var reg = /object/g
if(reg.test(<eachline>)){
// write new line
}else{
// do nothing
}