Make string checker more efficient - c#

I am using the following code to check if a string is contained within another string -
foreach (string testrecord in testlist)
{
foreach (string realrecord in reallist)
{
if ((Regex.Replace(testrecord , "[^0-9a-zA-Z]+", "")
.Contains((
Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "")))
&&
((Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "") != "")
&&
((Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "").Length >= 4)))))
{
matchTextBox.AppendText("Match: " + testrecord + " & " + realrecord + Environment.NewLine);
}
}
}
However the runtime for this to finish is taking quite a while. Since I added the special character regex removal the runtime is taking a lot longer however the regex is definitely required.
Is there a more efficient way of applying this regex? I tried to add it to the foreach string variables however you cannot alter them as they are in a foreach loop.

Optimized version:
// Do not put text into matchTextBox direct:
// it makes the control re-painting each time you change the text
// Instead, collect all the text into StringBuffer
StringBuilder Sb = new StringBuilder();
// Pull out as much as you can from the inner loop,
// that's why I've changed the loops' order:
// first loop on reallist, then on testlist
foreach (string realrecord in reallist) {
// Cache Regex.Replace result
String realCleaned = Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "");
// Test as early as possible
if (realCleaned.Length < 4)
continue;
// You don't need to test realCleaned != "";: realCleaned.Length < 4 is enough
foreach (string testrecord in testlist) {
// Cache Regex.Replace result: it's a little bit overshoot here, but if some
// more tests are added it'll be helpful
String testCleaned = Regex.Replace(testrecord, "[^0-9a-zA-Z]+", "");
if (testCleaned.Contains(realCleaned))
Sb.AppendLine("Match: " + testrecord + " & " + realrecord);
}
}
// At last matchTextBox.Text change
matchTextBox.AppendText(Sb.ToString());

This should be a bit quicker (one regex operation per testrecord):
var strippedRealList = reallist.Select(s => Regex.Replace(s, "[^0-9a-zA-Z]+", ""))
.Where(s => s.Length >= 4)
.ToArray();
foreach (string realrecord in reallist)
{
strippedRealList.Where(s => realrecord.Contains(s))
.ToList()
.ForEach(s =>
matchTextBox.AppendText("Match: "
+ s
+ " & "
+ realrecord
+ Environment.NewLine));
}

I wonder that you are using Regex to achieve your purpose ignoring the fact that you can also achieve this by only using .Contains() method such that your code should be simple and faster then before
foreach (string testrecord in testlist)
{
foreach (string realrecord in reallist)
{
if(testrecord.Contains(realrecord))
{
matchTextBox.AppendText("Match: " + testrecord + " & " + realrecord + Environment.NewLine);
}
}
}

Related

how to copy multiple line from text file C#

I need to copy multiple lines from text file(cisco config file): based on the below condition
if the line starts with interface copy from interface until '! '
my file is like :
!
access-list 1>
!
interface 1
ip address xx.xx.xx.xx
!
interface 2
ip address xx.xx.xx.xx
!
route 1
!
I try the below code :
var lines = File.ReadAllLines("C:\\My File2.txt");
foreach (var line1 in lines){
string firstWord = line1.Split(' ').First();
if ((firstWord == "access-list") && (!line1.Contains("remark ")))
{
TextBox1.Text = TextBox1.Text + "\r\n" + line1;
}
else if (firstWord == "nat")
{
TextBox2.Text = TextBox2.Text + "\r\n" + line1;
}
else if (firstWord == "interface")
{
var result = lines.Substring(line1.LastIndexOf('!') + 1);
TextBox3.Text = TextBox3.Text + "\r\n" + result;
}
but I get only one line as output
In case you want to keep your algorithm, this will work for you.
var lines = File.ReadAllLines("C:\\My File2.txt");
int i;
for (i = 0; i<lines.Length;i++)
{
var line1 = lines[i];
if (line1 == "!" || line1 == " ") continue;
if (line1.StartsWith("access-list")) && (!line1.Contains("remark ")))
{
TextBox1.Text = TextBox1.Text + "\r\n" + line1;
}
else if (line1.StartsWith("nat"))
{
TextBox2.Text = TextBox2.Text + "\r\n" + line1;
}
if (line1.StartsWith("interface"))
{
var str = line1;
while (!Equals(lines[i + 1], "!"))
{
str += lines[i + 1];
i++;
}
TextBox3.Text = TextBox3.Text + "\r\n" + str;
}
}
As per the file structure shown by you interface and ip address are on different lines. So you won't get it in same iteration of for loop. When you find that firstWord == "interface" you will need to set a flag that will tell you that next line is ip address and in next iteration check if that flag is true parse the current line as ip address and process it the way you want.
You should use "File.ReadAllText" instead of "File.ReadAllLines". "File.ReadAllText" returns a string with the complete text file text. After that, you can use the "String.Split" method to generate a string array.
var lines = File.ReadAllText("C:\\My File2.txt");
var seperatedStrings = lines.Split('!');
Each index of "seperatedStrings" contains what you want.
UPDATE: Here is a code snippet, that can help:
var lines = File.ReadAllText("C:\\My File2.txt");
var seperatedStrings = lines.Split('!');
foreach (var oneString in seperatedStrings)
{
if (oneString.Contains("access-list"))
{
Console.WriteLine("Access-List: " + oneString);
}else if (oneString.Contains("nat"))
{
Console.WriteLine("Nat: " + oneString);
}else if (oneString.Contains("interface"))
{
Console.WriteLine("Interface: " + oneString);
}
}
This is the output of my code snippet:

A Loop unnecessarily requires MessageBox, freezes if removed

I have a C# code that when it runs, it feeds approximately 200 values into separate lines in a multi-line enabled textbox but a messagebox in the middle, which I put just to be sure it's feeding the correct data, now freezes the whole code if removed. I couldn't understand the significance of it, previous textboxes handled heavier loads with little trouble but apparently this one require a short break or at least some sort of human interaction(luckily only pressing the OK button on a messagebox) so I was wondering if there is a solution or a way around it like a similar stop but not requiring my guidance. It's not convenient to press a key 200+ times just to get one group of data out of many.
Below is the code, just in case:
if (listBox3.SelectedIndex < 0 || listBox4.SelectedIndex < 0) {
MessageBox.Show("Select the Chart Parameters(E.g.: BTC-USD)");
}
if (listBox4.GetItemText(listBox4.SelectedItem).Contains(listBox3.GetItemText(listBox3.SelectedItem))) {
MessageBox.Show("Please select seperate pairs.(E.g.: NOT BTC-BTC but e.g.:BTC-USD)");
}
else
{
string url = textBox8.Text + listBox3.GetItemText(listBox3.SelectedItem) + listBox4.GetItemText(listBox4.SelectedItem);
MessageBox.Show(url);
System.Net.WebClient client8 = new System.Net.WebClient();
var html = client8.DownloadString(url);
string s = html.Replace("[[", "[");
string ss = s.Replace("]]", "]");
textBox9.Text = ss;
dynamic obj1 = JsonConvert.DeserializeObject(ss); //ss is the data
var timezz = (Int32)obj1.SelectToken("time");
textBox11.Text = textBox11.Text + timezz;
var data1m = (string)obj1.SelectToken("data1m");
ICollection<string> matches =
Regex.Matches(data1m, #"\[([^]]*)\]", RegexOptions.Multiline)
.Cast<Match>()
.Select(x => x.Groups[1].Value)
.ToList();
foreach (string match in matches) { textBox10.Text += Environment.NewLine + match; }
for (int i = 1; i < textBox10.Lines.Length; i++)
{
string linebyline = textBox10.Lines[i];
var resultString = Regex.Match(linebyline, #"\d+").Value;
//uni_time = resultString;
var yen = linebyline.Replace(resultString, string.Empty);
MessageBox.Show(yen);
/////WHY DOES IT NEEDS TO BE STOPPED BY THIS MSGBOX INORDER2 EXECUTE THE WHOLE CODE???
//////IF I REMOVE IT, IT FREEZES
var resultz = yen.Substring(yen.LastIndexOf(',') + 1);
//uni_vol = resultz;
var ztring = yen.Replace(resultz, string.Empty);
//MessageBox.Show(ztring);
//Regex re = new Regex(#"\d+(\.\d{1,4})?");
ICollection<string> mc = Regex.Matches(ztring, #"\d+(\.\d{1,4})?").Cast<Match>()
.Select(x => x.Groups[0].Value)
.ToList();
foreach (string m in mc)
{
//MessageBox.Show(m);
if (textBox13.Text == string.Empty) { textBox13.Text += m; }
else
{
textBox13.Text += Environment.NewLine + m;
}
}
}
}

Adding text items from a csv file, to a listbox only when certain a string matches a string from that csv file

So I've been trying to figure out how to bring an entire line of a .csv file but only the ones who's first string matches another one.
This is what I got so far, all im getting back in my listbox is info from the same random line.
If you guys can help me with the logic it would help out a lot thanks
cbocustinfo.Items.Clear();
lstcustinfo.Items.Clear();
StreamReader infile, transdata;
infile = File.OpenText(#"E:\AS2customers.csv");
transdata= File.OpenText(#"E:\AS2data.csv");
string[] custinfo, names;
string[] custtrans;
do
{
custtrans = transdata.ReadLine().Split(',');
if (custinfo[1] == custtrans[0])
{
lstcustinfo.Items.Add(custtrans[3] + " " + custtrans[4]);
}
}
while (transdata.EndOfStream != True);
infile.Close();
transdata.Close();
Here is where I initialize custinfo
do
{
custinfo = infile.ReadLine().Split(',');
names = custinfo[0].Split(' ');
cbocustinfo.Items.Add(names[0] +" "+ names[1]+ " " + custinfo[1]);
}
while (infile.EndOfStream != true);
If I understand what you're trying to do correctly, maybe it would be easier to just read the files into two strings, then do the splitting and looping over those. I don't know your file formats, so this may be doing unnecessary processing (looping through all the transactions for every customer).
For example:
cbocustinfo.Items.Clear();
lstcustinfo.Items.Clear();
var customers = File.ReadAllText(#"E:\AS2customers.csv")
.Split(new []{Environment.NewLine}, StringSplitOptions.None);
var transactions = File.ReadAllText(#"E:\AS2data.csv")
.Split(new []{Environment.NewLine}, StringSplitOptions.None);
foreach (var customer in customers)
{
var custInfo = customer.Split(',');
var names = custInfo[0].Split(' ');
cbocustinfo.Items.Add(names[0] + " " + names[1]+ " " + custinfo[1]);
foreach (var transaction in transactions)
{
var transInfo = transaction.Split(',');
if (custInfo[1] == transInfo[0])
{
lstcustinfo.Items.Add(transInfo[3] + " " + transInfo[4]);
}
}
}

String list remove

I have this code:
List<string> lineList = new List<string>();
foreach (var line in theFinalList)
{
if (line.PartDescription != "")
lineList.Add(line.PartDescription + " " + line.PartNumber + "\n");
else
lineList.Add("N/A " + line.PartNumber + "\n");
//
//This is what I am trying to fix:
if (lineList.Contains("FID") || lineList.Contains("EXCLUDE"))
// REMOVE THE item in the lineList
}
I am trying to go through theFinalList in a foreach loop and add each line to a new list called lineList.
Once added, I want to remove any entries from that list that contain the text "FID" or "EXCLUDE".
I am having trouble removing the entry, can someone help me?
why add them when you want to remove them right after:
lineList = theFinalList.Select( line =>
{
if (line.PartDescription != "")
return line.PartDescription + " " + line.PartNumber + "\n";
else
return "N/A " + line.PartNumber + "\n";
})
.Where(x => !(x.Contains("FID") || x.Contains("EXCLUDE")))
.ToList();
The following code sample iterates through the lineList and removes lines that contain FID or EXCLUDE.
for(int i = lineList.Count - 1; i >= 0; i--)
{
if (lineList[i].Contains("FID") || lineList[i].Contains("EXCLUDE"))
lineList.RemoveAt(i);
}
It is important to traverse a list in reverse order when deleting items.
You can't remove the items in your theFinalList list while you are iterating over theFinalList in a foreach loop. In this case, you may get System.InvalidOperationException with the message “Collection was modified; enumeration operation may not execute.”
you have to do something like this:
List<string> removals = new List<string>();
foreach (string s in theFinalList)
{
//do stuff with (s);
removals.Add(s);
}
foreach (string s in removals)
{
theFinalList.Remove(s);
}
try
foreach (var line in theFinalList)
{
string T = "";
if (line.PartDescription != "")
T = line.PartDescription + " " + line.PartNumber + "\n";
else
T = "N/A " + line.PartNumber + "\n";
if (!(T.Contains("FID") || T.Contains("EXCLUDE"))
lineList.Add (T);
}
I think its more logical approach
Regex exclude = new Regex("FID|EXCLUDE");
foreach (var line in theFinalList.Where(
ln => !exclude.Match(ln.PartDescription).Success &&
!exclude.Match(ln.PartNumber ).Success))){
string partDescription = "N/A";
if(!string.IsNullOrWhiteSpace(line.PartDescription)){
partDescription = line.PartDescription;
}
lineList.Add(partDescription + " " + line.PartNumber + "\n");
}
edit regex for your needs (ignore case maybe or multiline, probably compiled too) and feel free to replace "\n" with Environment.NewLine
Try this:
var excludingTexts = new [] { "FID", "EXCLUDE" }
lineList = lineList.Where(y => !excludingTexts.Any(x => line.PartDescription.Contains(x) || line.PartNumber.Contains(x))).ToList();
Or you can rewrite it as:
var excludingTexts = new [] { "FID", "EXCLUDE" }
List<string> lineList = (from line in theFinalList
where !excludingTexts.Any(x => line.PartDescription.Contains(x) || line.PartNumber.Contains(x))
select line.PartDescription != "" ?
line.PartDescription + " " + line.PartNumber + "\n" :
"N/A " + line.PartNumber + "\n"
).ToList();

adding line break

I have a problem with adding line break in a string. I have tried using "\r\n", and Environment.NewLine also does not work.
FirmNames = "";
foreach (var item in FirmNameList)
{
if (FirmNames != "")
{
FirmNames += ", " + LineBreak; -- I want a line break here after the comma ","
}
FirmNames += item;
}
Can anyone help?
The correct answer is to use Environment.NewLine, as you've noted. It is environment specific and provides clarity over "\r\n" (but in reality makes no difference).
foreach (var item in FirmNameList)
{
if (FirmNames != "")
{
FirmNames += ", " + Environment.NewLine;
}
FirmNames += item;
}
Give this a try.
FirmNames = String.Join(", \n", FirmNameList);
C# 6+
In addition, since c#6 you can also use a static using statement for System.Environment.
So instead of Environment.NewLine, you can just write NewLine.
Concise and much easier on the eye, particularly when there are multiple instances ...
using static System.Environment;
...
foreach (var item in FirmNameList)
{
if (FirmNames != "")
{
FirmNames += ", " + NewLine;
}
FirmNames += item;
}
This worked for me:
foreach (var item in FirmNameList){
if (FirmNames != "")
{
FirmNames += ",\r\n"
}
FirmNames += item;
}
Try using \n when concatenating strings, as in this example:
var name = "Raihan";
var ID = "1234";
Console.WriteLine(name + "\n" + ID);
\n in c3 working correctly
using System;
namespace testing2
public class Test {
public static void Main(string[] args) {
Console.WriteLine("Enter your name");
String s = Console.ReadLine();
Console.WriteLine("Your name is " + s + "\n" + "Thank You");
}
}
There are many ways to do it, in my case I use several because some don't work on the platform I need, you can try the following:
Environment.NewLine //--> recommendable
\n
\r
\n\r
\r\n
3 WAYS TO INSERT A NEW LINE IN C#
1:
Console.WriteLine("This is a line");
Console.WriteLine();
Console.WriteLine("This is another line");
2:
Console.WriteLine("This is a line.\nThis is another line.");
3:
Console.WriteLine("This is a line." + Environment.NewLine + "This is another line.");
string[] abcd = obj.show();
Response.Write(string.join("</br>", abcd));

Categories

Resources