I have a text file like so:
template.txt
hello my name is [MYNAME], and i am of age [AGE].
i live in [COUNTRY].
i love to eat [FOOD]
and I am trying to replace whatever is in the square brackets with strings from a list example
// // name //country // age // food
p.Add(new Person("jack", "NZ", "20", "Prawns"));
p.Add(new Person("ana", "AUS", "23", "Chicken"));
p.Add(new Person("tom", "USA", "30", "Lamb"));
p.Add(new Person("ken", "JAPAN", "15", "Candy"));
so far I have tried the below function which I call inside a loop
//loop
static void Main(string[] args)
{
int count = 0;
foreach (var l in p)
{
FindAndReplace("template.txt","output"+count+".txt" ,"[MYNAME]",l.name);
FindAndReplace("template.txt","output"+count+".txt" ,"[COUNTRY]",l.country);
FindAndReplace("template.txt","output"+count+".txt" ,"[AGE]",l.age);
FindAndReplace("template.txt","output"+count+".txt" ,"[FOOD]",l.food);
count++;
}
}
//find and replace function
private static void FindAndReplace(string template_path,string save_path,string find,string replace)
{
using (var sourceFile = File.OpenText(template_path))
{
// Open a stream for the temporary file
using (var tempFileStream = new StreamWriter(save_path))
{
string line;
// read lines while the file has them
while ((line = sourceFile.ReadLine()) != null)
{
// Do the word replacement
line = line.Replace(find, replace);
// Write the modified line to the new file
tempFileStream.WriteLine(line);
}
}
}
}
this is what I have done. But the output I get is this
output1.txt
hello my name is [MYNAME], and i am of age [AGE].
i live in [COUNTRY].
i love to eat Prawns
output2.txt
hello my name is [MYNAME], and i am of age [AGE].
i live in [COUNTRY].
i love to eat Chicken
Only the last text is replaced.
Every time you call FindAndReplace you are overwriting the last file written.
When you call it the first time it reads the template file, replaces a specific placeholder ([MYNAME]) with a value and writes it to a new file.
In the next call you take the template again so [MYNAME] is not replaced anymore and only replaces the country and writes it to the same file overwriting the content. This repeats till you get to the last call.
That is why only [FOOD] is replaced.
Try replacing all the text in one go and then writing it to the file.
instead of a function try doing something like this
static void Main(string[] args)
{
int count = 0;
foreach (var l in p)
{
using (var sourceFile = File.OpenText("template.txt"))
{
// Open a stream for the temporary file
using (var tempFileStream = new StreamWriter("output" + count + ".txt"))
{
string line;
// read lines while the file has them
while ((line = sourceFile.ReadLine()) != null)
{
line = line.Replace("[MYNAME]", l.name);
line = line.Replace("[COUNTRY]", l.country);
line = line.Replace("[AGE]", l.age);
line = line.Replace("[FOOD]", l.food);
tempFileStream.WriteLine(line);
}// end of while loop
}
count++;
}//end foreach loop
}
}//end of main
Related
The text i am reading from has a couple lines.
I want to add new lines to it such as date, cost, intro.
I think I can manually enter it but I would like to know if it is possible to read each line and print it into the new file along with the new inputs on separate lines. Would like to use stream reader and stream writer still as it seems the simplest one I could find online.
The only thing it seems to print is: System.IO.StreamReader
//WRITE FILE
public void writeFile()
{
GroceryItem readGroceryList = new GroceryItem();
string[] lines = { "Grocery for you", Convert.ToString(DateTime.Now), readFile() };
StreamWriter file = new StreamWriter("c:\\MicrosoftVisual\\invoice.txt");
foreach (string line in lines)
{
file.WriteLine(line);
file.Flush();
}
}
public string readFile() // to adjust name of method later if require
{
//READ FILE
StreamReader myReader = new StreamReader("groceries.txt");
string consoleLine = "";
while (consoleLine != null)
{
consoleLine = myReader.ReadLine();
if (consoleLine != null)
{
return Convert.ToString(myReader);
}
}
return consoleLine;
}
public GroceryItem (string n, double p)
Your main problem lies in the readFile method. I think your intension is to read all lines and not just one line and then return your reader as string. To do this I would collect all the lines in a List<string> and return that, like so:
public List<string> ReadFile()
{
StreamReader myReader = new StreamReader("groceries.txt");
List<string> list = new List<string>(); // Create an empty list of strings
while (myReader.Peek() >= 0) // Checks if the stream has reacht the end of the file.
{
list.Add(myReader.ReadLine()); // Reads a line out of the files and appends it to the list.
}
return list; // Returns the list from the method.
}
With these changes you also need to adjust your writeFile method, like so:
public void WriteFile()
{
List<string> lines = ReadFile();
// Calls ReadFile to get the already exsisting lines from the file.
lines.Add("Grocery for you"); // You can add new lines now.
lines.Add(DateTime.Now.ToString());
StreamWriter file = new StreamWriter("c:\\MicrosoftVisual\\invoice.txt");
foreach (string line in lines)
{
file.WriteLine(line);
}
file.Flush(); // You only need to call Flush once when you are finished writing to the Stream.
}
There is even a simpler variant without Streams by using C#'s File helper class.
List<string> lines = new List<string>(File.ReadAllLines("groceries.txt"));
// Reads all lines from the file and puts them into the list.
lines.Add("Grocery for you"); // You can add new lines now.
lines.Add(DateTime.Now.ToString());
File.WriteAllLines("c:\\MicrosoftVisual\\invoice.txt", lines);
So, I am trying to check the contents of a text file to see if any of the values contained within the List textwords exist within the text file.
However when the code is executed it always thinks the message doesn't contain any of the strings contained within the textwords List.
The code used is below.
Any help with this would be greatly appreciated.
List<string> textwords = new List<string>();
using (var UnacceptableWords = new StreamReader("fileLocation"))
{
while (!UnacceptableWords.EndOfStream)
{
string[] row = UnacceptableWords.ReadLine().Split(',');
string Column1 = row[0];
textwords.Add(Column1);
}
}
directory = new DirectoryInfo("filelocation");
files = directory.GetFiles("*.txt");
foreach (FileInfo file in files)
{
using(StreamReader Message = new StreamReader(file.FullName))
{
string MessageContents = Message.ReadToEnd();
if(MessageContents.Contains(textwords.ToString()))
{
MessageBox.Show("found a word");
}
MessageBox.Show("message clean");
}
}
The string.Cointains() method takes in a string but you are passing into it the List, which you have turned into a string.
List.ToString() != Values contained in the List as strings
To do this you must iterate through the array and pass each element of it at a time
foreach(string keyword in textwords)
{
if(MessageContents.Contains(keyword))
{
MessageBox.Show("found a word");
break;
}
}
So I have a generic number check that I am trying to implement:
public static bool isNumberValid(string Number)
{
}
And I want to read the contents of a textfile (only contains numbers) and check each line for the number and verify it is the valid number using isNumberValid. Then I want to output the results to a new textfile, I got this far:
private void button2_Click(object sender, EventArgs e)
{
int size = -1;
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
try
{
string text = File.ReadAllText(file);
size = text.Length;
using (StringReader reader = new StringReader(text))
{
foreach (int number in text)
{
// check against isNumberValid
// write the results to a new textfile
}
}
}
catch (IOException)
{
}
}
}
Kind of stuck from here if anyone can help?
The textfile contains several numbers in a list:
4564
4565
4455
etc.
The new textfile I want to write would just be the numbers with true or false appended to the end:
4564 true
You don't need to read the entire file into memory all at once. You can write:
using (var writer = new StreamWriter(outputPath))
{
foreach (var line in File.ReadLines(filename)
{
foreach (var num in line.Split(','))
{
writer.Write(num + " ");
writer.WriteLine(IsNumberValid(num));
}
}
}
The primary advantage here is a much smaller memory footprint, as it only loads a small part of the file at a time.
You could try this to keep with the pattern you were initially following...
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
try
{
using (var reader = new StreamReader(file))
{
using (var writer = new StreamWriter("results.txt"))
{
string currentNumber;
while ((currentNumber = reader.ReadLine()) != null)
{
if (IsNumberValid(currentNumber))
writer.WriteLine(String.Format("{0} true", currentNumber));
}
}
}
}
catch (IOException)
{
}
}
}
public bool IsNumberValid(string number)
{
//Whatever code you use to check your number
}
You need to replace your loop to look like this:
string[] lines = File.ReadAllLines(file);
foreach (var s in lines)
{
int number = int.Parse(s);
...
}
This would read each line of file, assuming that there is only one number per line,
and lines are separated with CRLF symbols. And parse each number to integer, assuming that integer is not greater than 2,147,483,647 and not less than -2,147,483,648, and integers are stored in your locale settings, with or without group separators.
In case if any line is empty, or contains non-integer - code will throw an exception.
You could try something like this:
FileStream fsIn = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
using (StreamReader sr = new StreamReader(fsIn))
{
line = sr.ReadLine();
while (!String.IsNullOrEmpty(line)
{
line = sr.ReadLine();
//call isNumberValid on each line, store results to list
}
}
Then print the list using FileStream.
As other people have mentioned, your isNumberValid method could make use of the Int32.TryParse method, but since you said your text file only contains numbers this may not be necessary. If you're just trying to match the number exactly, you can use number == line.
First, load all lines of the input file in a string array,
then open the output file and loop over the array of strings,
Split each line at the space separator and pass every part to your static method.
The static method use Int32.TryParse to determine if you have a valid integer or not without throwing an exception if the input text is not a valid Int32 number.
Based on the result of the method write to the output file the desidered text.
// Read all lines in memory (Could be optimized, but for this example let's go with a small file)
string[] lines = File.ReadAllLines(file);
// Open the output file
using (StringWriter writer = new StringWriter(outputFile))
{
// Loop on every line loaded from the input file
// Example "1234 ABCD 456 ZZZZ 98989"
foreach (string line in lines)
{
// Split the current line in the wannabe numbers
string[] numParts = line.Split(' ');
// Loop on every part and pass to the validation
foreach(string number in numParts)
{
// Write the result to the output file
if(isNumberValid(number))
writer.WriteLine(number + " True");
else
writer.WriteLine(number + " False");
}
}
}
// Receives a string and test if it is a Int32 number
public static bool isNumberValid(string Number)
{
int result;
return Int32.TryParse(Number, out result);
}
Of course this works only if your definition of 'number' is equal to the allowed values for a Int32 datatype
I am working on a method that reads txt file with multiple lines and then turns it into a txt file with only single line.
Like this:
first line,
second line,
third line.
Into this:
first line, second line, third line.
I have this code but it only shows "third line." in file:
MAIN:
static void Main(string[] args)
{
string fLine= "first line,\n second line,\n third line.";
string sLine= "";
Console.Write(fLine);
Console.WriteLine();
Console.Write(sLine);
string filDat1 = "D:\\Dat1.txt";
string filDat2 = "D:\\Dat2.txt";
if (File.Exists(filDat1))
Console.WriteLine("File already exist!");
else
{
File.WriteAllText(filDat1, fLine);
}
File.WriteAllText(filDat2, sLine);
changeFile(filDat1);
Console.ReadKey();
}
METHOD:
public static void changeFile(string name)
{
StringBuilder dato;
string filDat2 = "D:\\Dat2.txt";
try
{
string[] lines = File.ReadAllLines(name);
foreach (string line in lines)
{
Console.WriteLine("Words in file: " + line);
}
Console.WriteLine();
Console.Write("New words in new file: ");
foreach (string line in lines)
{
string line1 = line;
dato = new StringBuilder();
line1 = line1.Replace("\n", " ");
for (int i = 0; i < line1.Count(); i++)
{
if (!line1[i].Equals(""))
{
dato.Append(line1[i] + "");
}
}
Console.WriteLine(dato);
File.WriteAllText(filDat2, dato.ToString());
}
}
I don't know what I'm doing wrong. I only get the last word in my case "third word." in new file Dat2.txt.
Also, is there any way to create a method that can take two files. One file to read and one file to write that changed text to it?
Here is a method to make anew file for given file with only 1 line:
public static void changeFile(string InputPath,string OutputPath)
{
List<string> OUTPUT = new List<string>();
StreamReader sr = new StreamReader(InputPath);
while (!sr.EndOfStream)
{
OUTPUT.Add(sr.ReadLine());
}
sr.Close();
StreamWriter fs = new StreamWriter(OutputPath);
string output = "";
foreach (string line in OUTPUT)
{
output += line + " ";
}
fs.WriteLine(output);
fs.Close();
}
In case you were curious as to why your approach didn't work, it was because you reset dato every iteration, just move that outside and away you go, I've also moved the write outside too since you only need to do that once.
dato = new StringBuilder();
foreach (string line in lines)
{
string line1 = line;
line1 = line1.Replace("\n", " ");
for (int i = 0; i < line1.Count(); i++)
{
if (!line1[i].Equals(""))
{
dato.Append(line1[i] + "");
}
}
Console.WriteLine(dato);
}
File.WriteAllText(filDat2, dato.ToString());
I am rookie in C#, but I need solve one Problem.
I have several text files in Folder and each text files has this structure:
IdNr 000000100
Name Name
Lastname Lastname
Sex M
.... etc...
Load all files from Folder, this is no Problem ,but i need delete "zero" in IdNr, so delete 000000 and 100 leave there. After this file save. Each files had other IdNr, Therefore, it is harder :(
Yes, it is possible each files manual edit, but when i have 3000 files, this is not good :)
Can C# one algorithm, which could this 000000 delete and leave only number 100?
Thank you All.
Vaclav
So, thank you ALL !
But in the End I have this Code :-) :
using System.IO;
namespace name
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Browse_Click(object sender, EventArgs e)
{
DialogResult dialog = folderBrowserDialog1.ShowDialog();
if (dialog == DialogResult.OK)
TP_zdroj.Text = folderBrowserDialog1.SelectedPath;
}
private void start_Click(object sender, EventArgs e)
{
try
{
foreach (string file in Directory.GetFiles(TP_zdroj.Text, "*.txt"))
{
string text = File.ReadAllText(file, Encoding.Default);
text = System.Text.RegularExpressions.Regex.Replace(text, "IdNr 000*", "IdNr ");
File.WriteAllText(file, text, Encoding.Default);
}
}
catch
{
MessageBox.Show("Warning...!");
return;
}
{
MessageBox.Show("Done");
}
}
}
}
Thank you ALL ! ;)
You can use int.Parse:
int number = int.Parse("000000100");
String withoutzeros = number.ToString();
According to your read/save file issue, do the files contain more than one record, is that the header or does each record is a list of key and value like "IdNr 000000100"? It's difficult to answer without these informations.
Edit: Here's a simple but efficient approach which should work if the format is strict:
var files = Directory.EnumerateFiles(path, "*.txt", SearchOption.TopDirectoryOnly);
foreach (var fPath in files)
{
String[] oldLines = File.ReadAllLines(fPath); // load into memory is faster when the files are not really huge
String key = "IdNr ";
if (oldLines.Length != 0)
{
IList<String> newLines = new List<String>();
foreach (String line in oldLines)
{
String newLine = line;
if (line.Contains(key))
{
int numberRangeStart = line.IndexOf(key) + key.Length;
int numberRangeEnd = line.IndexOf(" ", numberRangeStart);
String numberStr = line.Substring(numberRangeStart, numberRangeEnd - numberRangeStart);
int number = int.Parse(numberStr);
String withoutZeros = number.ToString();
newLine = line.Replace(key + numberStr, key + withoutZeros);
newLines.Add(line);
}
newLines.Add(newLine);
}
File.WriteAllLines(fPath, newLines);
}
}
Use TrimStart
var trimmedText = number.TrimStart('0');
This should do it. It assumes your files have a .txt extension, and it removes all occurrences of "000000" from each file.
foreach (string fileName in Directory.GetFiles("*.txt"))
{
File.WriteAllText(fileName, File.ReadAllText(fileName).Replace("000000", ""));
}
These are the steps you would want to take:
Loop each file
Read file line by line
for each line split on " " and remove leading zeros from 2nd element
write the new line back to a temp file
after all lines processed, delete original file and rename temp file
do next file
(you can avoid the temp file part by reading each file in full into memory, but depending on your file sizes this may not be practical)
You can remove the leading zeros with something like this:
string s = "000000100";
s = s.TrimStart('0');
Simply, read every token from the file and use this method:
var token = "000000100";
var result = token.TrimStart('0');
You can write a function similar to this one:
static IEnumerable<string> ModifiedLines(string file) {
string line;
using(var reader = File.OpenText(file)) {
while((line = reader.ReadLine()) != null) {
string[] tokens = line.Split(new char[] { ' ' });
line = string.Empty;
foreach (var token in tokens)
{
line += token.TrimStart('0') + " ";
}
yield return line;
}
}
}
Usage:
File.WriteAllLines(file, ModifiedLines(file));