I need to replace multiple strings in a textfile. This is my code:
List<string> list = new List<string>();
string Text = File.ReadAllText(temp);
list.Add(Text.Replace("name", name));
list.Add(Text.Replace("name2", name2));
list.Add(Text.Replace("1.0000", CR));
list.Add(Text.Replace("0.6590", CG));
list.Add(Text.Replace("0.0000", CB));
foreach (string txt in list)
{
File.WriteAllText(path, txt);
}
When I debug I can see the strings beeing replaced one after one, but when the next string is about to be replaced, the last string will then go back to its old value. Is there a way to replace multiple strings in a textfile?
You don't need a list for this, but you do need to save the changes in the resulting string each time you do a replacement, otherwise you lose the changes.
The Replace method returns a new string with the replacement, so you can chain the calls to Replace and it will end up returning a string with all your changes.
Here's an example:
string text = File.ReadAllText(temp)
.Replace("name", name)
.Replace("name2", name2)
.Replace("1.0000", CR)
.Replace("0.6590", CG)
.Replace("0.0000", CB);
File.WriteAllText(path, txt);
Related
I have a function that is giving me a Console.Writeline output, but it's not writing the information to my richTextBox.
public static void FindFeatureSecurityEsc(string[] actualFontName, string displayFontName, string dragDropSourceData, string outputData)
{
//Create a list to hold all the fonts
var listOfDisplayFonts = new List<string>();
string[] arrayOfDisplayFonts = listOfDisplayFonts.ToArray();
//Display font name for each font that exists in the dragdrop rich text box.
if (dragDropSourceData.Contains(actualFontName[0]) || dragDropSourceData.Contains(actualFontName[1]) || dragDropSourceData.Contains(actualFontName[2]))
{
//If the font doesn't already exist in the output textbox.
if (!outputData.Contains(displayFontName))
{
//Add font to the output textbox.
listOfDisplayFonts.Add(displayFontName);
foreach (string s in listOfDisplayFonts)
{
//Add strings from list to text box.
outputData += string.Join(Environment.NewLine, s) + "\n";
}
//Clear fonts from the list (They've already been added to the textboxes).
listOfDisplayFonts.Clear();
}
}
Console.WriteLine(outputData);
}
In this example, outputData is equal to richTextBox1.Text (the last parameter). When I am using this function in my Main.cs, these are the parameters.
FontFinder.FindFeatureSecurityEsc(EscapeSequence.fontEsc12pt, EscapeSequence.fontDispName, dragDropRichTextBox1.Text, richTextBox1.Text);
Why is it that the Console.Writeline is giving me the proper output, but richTextBox1.Text remains empty? I know the function is proper, because if I call it directly from my Main.cs (and fill the actual parameter values into the function), it works fine. This is mostly an educational exercise to help me learn.
You're passing the text string of richTextBox1 to the method. The statement outputData += string.Join(Environment.NewLine, s) + "\n"; would concatenate text and create a new string (a string is immutable) but the original text string that was passed remains the same.
You need to assign back the result to richTextBox1:
richTextBox1.Text = FontFinder.FindFeatureSecurityEsc(EscapeSequence.fontEsc12pt,
EscapeSequence.fontDispName, dragDropRichTextBox1.Text, richTextBox1.Text);
Of course in this case you should change the method's return type from void to string and return outputData; at the end.
In this example, outputData is equal to richTextBox1.Text (the last parameter).
It might have the same string value when you start, but it is not the same variable.
You pass in outputData.
FindFeatureSecurityEsc(string[] actualFontName, string displayFontName, string dragDropSourceData, string outputData)
Then you modify it a bunch, and finally write it to the console.
Console.WriteLine(outputData);
You never assign your new outputData back to any control.
The outputData that you passed in is a different one than the final one you write to the console, because strings are immutable. That's a fancy way of saying you don't modify the original string, but rather you create a new one.
To solve the problem, assign outputData to the control. You can do that within the function you posted if it has access to the control, or it can return outputData back instead of having a void return type.
Quick fix:
At the end of your function, do this (obviously changing the return type to string from void as well):
return outputData;
So your function becomes:
public static string FindFeatureSecurityEsc(string[] actualFontName, string displayFontName, string dragDropSourceData, string outputData)
{
// everything the same as before...
return outputData;
}
Then you can call it like this:
richTextBox1.Text = FontFinder.FindFeatureSecurityEsc(EscapeSequence.fontEsc12pt,
EscapeSequence.fontDispName, dragDropRichTextBox1.Text,
richTextBox1.Text);
Strings are immutable. That means whenever you concatenate or do any other kind of string manipulation you are actually creating a new string. Your control's .Text property is still pointing to the old string so it won't "see" any of the changes.
The other approach here would be to change your function to take the control instead of the just the string:
public static void FindFeatureSecurityEsc(string[] actualFontName, string displayFontName, string dragDropSourceData, RichTextBox outputDataCtrl)
{
var outputData = outputDataCtrl.Text;
// rest of your function as before
outputDataCtrl.Text = outputData;
}
Which approach is better is up to you.
Looks like you are only using the richTextBox1.Text to display the output, since you are passing it by value. Hence the Console.Writeline output is correct. You would be able to get the result in the richTextBox.Text if you pass it by ref. That way you don't even have to change the return type of your method and assign it back to the control's text.
I have a few files, for example:
FileBegin Finance Open 87547.25 Close 548484.54 EndDay 4 End
Another file example:
FileBegin Finance Open 344.34 Close -3434.34 EndDay 5 End
I need to read the text in the file and replace only the numeric value after the word Open leaving the rest of the text before and after the word Open intact. I have been using this code:
string fileToRead = "c:\\file.txt";
public void EditValue(string oldValue, string newValue, Control Item)
{
if (Item is TextBox)
{
string text = File.ReadAllText(fileToRead);
text = text.Replace(oldValue, newValue);
File.WriteAllText(activeSaveFile, text);
}
}
What would be the best way of going about replacing just the numeric value after the word open?
Using Regular Expressions:
Regex rgx = new Regex(#"Open [^\s]+");
string result = rgx.Replace(text, newValue);
File.WriteAllText(activeSaveFile, result );
Using this approach, you can store the regex object outside the method so you avoid recompiling it each time. I'm guessing it won't have a significant performance impact compared to the file I/O in your case, but it is a good practice in other situations.
Split the row by the empty spaces like string.split(new char[] { ' ' }, StringSplitOptions.Empty) and then get the _splittedRow[3] and replace and merge the new row together.
If I understand you, the line:
FileBegin Finance Open 344.34 Close -3434.34 EndDay 5 End
is the entire file? And you have been typing in "344.34" for the old value and "something" for the new value? And you'd like to just type the new value only?
You could say:
string fileToRead = "c:\\file.txt";
public void EditValue(string oldValue, string newValue, Control Item)
{
if (Item is TextBox)
{
string text = File.ReadAllText(fileToRead);
string[] words = text.Split(new char[] {' '}); // assuming space-delimited
words[3] = "new value"; // replace the target value
text = "";
foreach (string w in words)
{
text += w + " "; // build our new string
}
File.WriteAllText(activeSaveFile, text.Trim()); // and write it back out
}
}
That's a lot of ifs, but I think this is what you mean. Also there are a lot of different ways to replace that one part of the string, I just thought this would give you the flexibility to do other things with a convenient array of words.
This is a program that reads in a CSV file, adds the values to a dictionary class and then analyses a string in a textbox to see if any of the words match the dictionary entry. It will replace abbreviations (LOL, ROFL etc) into their real words. It matches strings by splitting the inputted text into individual words.
public void btnanalyze_Click(object sender, EventArgs e)
{
var abbrev = new Dictionary<string, string>();
using (StreamReader reader = new StreamReader("C:/Users/Jordan Moffat/Desktop/coursework/textwords0.csv"))
{
string line;
string[] row;
while ((line = reader.ReadLine()) != null)
{
row = line.Split(',');
abbrev.Add(row[0], row[1]);
Console.WriteLine(abbrev);
}
}
string twitterinput;
twitterinput = "";
// string output;
twitterinput = txtInput.Text;
{
char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
string text = twitterinput;
string[] words = twitterinput.Split(delimiterChars);
string merge;
foreach (string s in words)
{
if (abbrev.ContainsKey(s))
{
string value = abbrev[s];
merge = string.Join(" ", value);
}
if (!abbrev.ContainsKey(s))
{
string not = s;
merge = string.Join(" ", not);
}
;
MessageBox.Show(merge);
}
The problem so far is that the final string is outputted into a text box, but only prints the last word as it overwrites. This is a University assignment, so I'm looking for a push in the correct direction as opposed to an actual answer. Many thanks!
string.Join() takes a collection of strings, concatenates them together and returns the result. But in your case, the collection contains only one item: value, or not.
To make your code work, you could use something like:
merge = string.Join(" ", merge, value);
But because of the way strings work, this will be quite slow, so you should use StringBuilder instead.
This is the problem:
string not = s;
merge = string.Join(" ", not);
You are just joining a single element (the latest) with a space delimiter, thus overwriting what you previously put into merge.
If you want to stick with string you need to use Concat to append the new word onto the output, though this will be slow as you are recreating the string each time. It will be more efficient to use StringBuilder to create the output.
If your assignment requires that you use Join to build up the output, then you'll need to replace the target words in the words array as you loop over them. However, for that you'll need to use some other looping mechanism than foreach as that doesn't let you modify the array you're looping over.
Better to User StringBuilder Class for such purpose
http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx
I need to read a block of data from this text. The block starts with the T|DataObject.EShop.Tic.TicVente| line and ends with T|DataObject.EShop.Tic.TicPaiement|.
I only want the lines that start with D between the previous strings.
W|301500120100407213036|
M|SYP||
T|DataObject.EShop.Tic.TicVente|
C|ArtId|ArtRef|PrxInit|QteArt|PrxEntId|TvaId|TvaTaux|RetourId|RetourMagAchat|RetourTicExtIdAchat|RetourDatAchat|PosteNum|TicId|LigNum|PrxAppel|PrxPaye|DatMaj|
D|18250168145|1825016814503131|1690|-1|0934489998|1|0|C|150||20100406000000|1|009700001|1|1690|1690|20100407093455|
D|18250137020|1825013702002161|750|1|1002689999|1|0|||||1|009700001|2|750|750|20100407093455|
D|18260013233|1826001323336111|1990|1|0935689998|1|0|||||1|009700002|1|1990|1990|20100407103918|
T|DataObject.EShop.Tic.TicPaiement|
C|PosteNum|TicId|LigNum|PaieId|Mnt|DevId|MntDev|Info1|Info2|TransId|TransOK|DatMaj|
D|1|009700001|1|01|-940|SYP|-940|||||20100407093455|
D|1|009700002|1|01|4000|SYP|4000|||||20100407103918|
T|DataObject.EShop.Tic.TicVenteAnnulee|
C|PosteNum|Dat|SessId|CliTypId|CliId|UtilId|LotId|ArtId|ArtRef|PrxInit|QteArt|PrxEntId|TvaId|TvaTaux|RetourId|RetourMagAchat|RetourTicExtIdAchat|RetourDatAchat|TicId|LigNum|PrxAppel|PrxPaye|DatMaj|
D|1|20100407105721|0097001|||6|0150010097763|18250040037|1825004003704121|990|1|1002689999|1|0|||||009700004|1|990|990|20100407213033|T|DataObject.EShop.Tic.TicVenteAnnulee|
C|PosteNum|Dat|SessId|CliTypId|CliId|UtilId|LotId|ArtId|ArtRef|PrxInit|QteArt|PrxEntId|TvaId|TvaTaux|RetourId|RetourMagAchat|RetourTicExtIdAchat|RetourDatAchat|TicId|LigNum|PrxAppel|PrxPaye|DatMaj|
D|1|20100407105721|0097001|||6|0150010097763|18250040037|1825004003704121|990|1|1002689999|1|0|||||009700004|1|990|990|20100407213033|
What about Regular Expressions?
You said:
starts in "T|DataObject.EShop.Tic.TicVente|" line
So it will begin with "^T|DataObject.EShop.Tic.TicVente|$"
You said:
T|DataObject.EShop.Tic.TicPaiement|
So it will end with "$T|DataObject.EShop.Tic.TicPaiement|$"
What else do you need? Each line starts with D? OK... try this
Regex rgx = new Regex("^T|DataObject.EShop.Tic.TicVente|$(D[.]*)$T|DataObject.EShop.Tic.TicPaiement|$", RegexOptions.MultiLine);
Or you can easily parse
set a flag indicating you are searching for your starting string
read lines until you find your start string (or EOF)
set a flag that indicates you are searching for the closing string
read lines until you find your ending string (or EOF)
when ending string found, set flag that
print all lines read between starting string and ending string
Well, you could find the first reference of T|DataObject, verify that it is the type you are looking for, then look for the next reference of T|DataObject.
Seems like it's just some simple string manipulation.
Is all of this on a single line or are the object header separated by carriage returns as well?
UPDATE
This is by no means the best way to do this and is just one possible way:
String sRecords = "T|DataObject.Test|C|RecordHeaderId|D|123|D|234|T|DataObject.Test2|C|RecordHeaderId|D|2345|D2366";
// this will split the string into an array on the boundary of |.
// which means you'll have all of item individual items separated out.
String[] sArray = sRecords.Split('|');
List<String> objects = new List<string>();
String obj = String.Empty;
foreach (String s in sArray) {
// locate the T item which defines a new record definition.
// the danger is if your data contains a "T" value somewhere it shouldn't
if (s.Equals("T") && !String.IsNullOrEmpty(obj)) {
objects.Add(obj);
obj = String.Empty;
}
obj = String.Format("{0}|{1}", obj, s);
}
objects.Add(obj);
// at this point "objects" hold a list of strings, each defined by the record type.
foreach (String s in objects) {
listBox1.Items.Add(s);
}
I have a string which consists of different fields. So what I want to do is get the different text and assign each of them into a field.
ex: Hello Allan IBM
so what I want to do is:
put these three words in different strings like
string Greeting = "Hello"
string Name = "Allan"
string Company = "IBM"
//all of it happening in a loop.
string data = "Hello Allan IBM"
string s = data[i].ToString();
string[] words = s.Split(',');
foreach (string word in words) {
Console.WriteLine(word);
}
any suggestions?
thanks hope to hear from you soon
If I understand correctly you have a string with place-holders and you want to put different string in those place-holders:
var format="{0}, {1} {2}. How are you?";
//string Greeting = "Hello"
//string Name = "Allan"
//string Company = "IBM"
//all of it happening in a loop.
string data = ...; //I think you have an array of strings separated by ,
foreach( va s in data){
{
//string s = data[i];//.ToString(); - it is already a string array
string[] words = data[i].Split(',');
Console.WriteLine(format, words[0], words[1], words[2]);
}
To me it sound not like a problem that can be solved with a loop. The essential problem is that the loop can only work if you do exactly the same operation on the items within the loop. If your problem doesn't fit, you end up with a dozen of lines of code within the loop to handle special cases, what could have been written in a shorter way without a loop.
If there are only two or three strings you have to set (what should be the case if you have named variables), assign them from the indexes of the split string. An alternative would be using regular expressions to match some patterns to make it more robust, if one of the expected strings is missing.
Another possibility would be to set attributes on members or properties like:
[MyParseAttribute(/*position*/ /*regex*/)]
string Greeting {get;set;}
And use reflexion to populate them. Here you could create a loop on all properties having that attribute, as it sounds to me that you are eager to create a loop :-)