I'm very new to c# and programming in general so I apologise if this doesn't make sense...
I need to be able to search a textbox or combobox to read a notepad file containing many satellite two line element codes.
The text file is set out like this:
0 VANGUARD 1
1 00005U 58002B 14242.42781498 .00000028 00000-0 24556-4 0 2568
2 00005 034.2497 271.4959 1848458 183.2227 175.4750 10.84383299975339
0 TRANSIT 2A
1 00045U 60007A 14245.43855606 .00000265 00000-0 95096-4 0 2208
2 00045 066.6958 193.0879 0251338 053.7315 060.2264 14.33038972819563
0 EXPLORER 11
1 00107U 61013A 14245.36883128 .00001088 00000-0 12832-3 0 1217
2 00107 028.7916 229.2883 0562255 219.9933 302.0575 14.05099145667434
Etc.
I need to search the box for the only satellite's name (the name after the 0 in the 'first' row) and extract that name into another textbox, and to use in my code. Additionally, I need to seperately extract the 2 lines of code directly beneath the name selected in the box (also to use in the code).
I have written code to use these two line elements, but I'm not able to automatically put them in my code.
Thank you
here is something that you can try quick and dirty that I have come up with.
1st place the file in a folder on your local hard drive.
2nd where I have filepath defined replace it with your actual file path and know how to use the # symbol and what it means in C#
3rd notice how I used the string .Replace Method.. you will have to tweak it I just gave you an Idea I am not going to write the entire code for you.. good luck.
static void Main(string[] args)
{
var fileName = string.Empty;
var filePath = #"C:\Users\myfolder\Documents\RGReports\"; //for testing purposes only
List<string> listNames = new List<string>();
string[] filePaths = Directory.GetFiles(#filePath);
foreach (string file in filePaths)
{
if (file.Contains(".txt"))
{
fileName = file;
using (StreamReader sr = File.OpenText(fileName))
{
//string s = String.Empty;
var tempFile = sr.ReadToEnd();
var splitFile = tempFile.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
foreach (string str in splitFile)
{
if (str.Length == 12)
{
listNames.Add(str.Substring(0, str.Length).Replace("0", "").Replace("1", "").Replace("2A",""));
}
Console.WriteLine(str);
}
}
}
}
}
Results will yield the following for names for example tested in a Console App
VANGUARD
TRANSIT
EXPLORER
You can use regular expressions for this task.
(I assume that the letters/numbers block after the name is also part of the name)
This code will do the following:
capture the name of the satellite and the two lines into a Satellite object
populate a ComboBox with the names of the satellite
whenever you selected a satellite you can know which one it was
a search box that searches for the first satellite beginning with the typed text
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
private readonly BindingList<Satellite> _satellites = new BindingList<Satellite>();
private string _input = #"
0 VANGUARD 1
1 00005U 58002B 14242.42781498 .00000028 00000-0 24556-4 0 2568
2 00005 034.2497 271.4959 1848458 183.2227 175.4750 10.84383299975339
0 TRANSIT 2A
1 00045U 60007A 14245.43855606 .00000265 00000-0 95096-4 0 2208
2 00045 066.6958 193.0879 0251338 053.7315 060.2264 14.33038972819563
0 EXPLORER 11
1 00107U 61013A 14245.36883128 .00001088 00000-0 12832-3 0 1217
2 00107 028.7916 229.2883 0562255 219.9933 302.0575 14.05099145667434
";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var regexObj =
new Regex(#"(?<=^\d+\s(?<name>[\w|\d|\s]+))\r\n(?<line1>(?<=^).*)\r\n(?<line2>(?<=^).*(?=\r))",
RegexOptions.Multiline);
Match matchResult = regexObj.Match(_input);
while (matchResult.Success)
{
string name = matchResult.Groups["name"].Value;
string line1 = matchResult.Groups["line1"].Value;
string line2 = matchResult.Groups["line2"].Value;
var regexObj1 = new Regex(#"(?<=^[1|2].*)([\d\w.-]+)");
Match matchResult1 = regexObj1.Match(line1);
var numbers1 = new List<string>();
while (matchResult1.Success)
{
string s = matchResult1.Value;
numbers1.Add(s);
matchResult1 = matchResult1.NextMatch();
}
var regexObj2 = new Regex(#"(?<=^[1|2].*)([\d\w.-]+)");
Match matchResult2 = regexObj2.Match(line2);
var numbers2 = new List<string>();
while (matchResult2.Success)
{
string s = matchResult2.Value;
numbers2.Add(s);
matchResult2 = matchResult2.NextMatch();
}
_satellites.Add(new Satellite
{
Name = name,
Line1 = line1,
Line2 = line2,
Numbers1 = numbers1,
Numbers2 = numbers2
});
matchResult = matchResult.NextMatch();
}
comboBox1.DataSource = _satellites;
comboBox1.DisplayMember = "Name";
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var comboBox = (ComboBox) sender;
var satellites = comboBox.DataSource as List<Satellite>;
if (satellites != null && comboBox.SelectedIndex > -1)
{
Satellite selectedSatellite = satellites[comboBox.SelectedIndex];
Console.WriteLine("Selected satellite: " + selectedSatellite.Name);
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
var textBox = (TextBox) sender;
string text = textBox.Text;
if (!string.IsNullOrWhiteSpace(text))
{
Satellite satellite =
_satellites.FirstOrDefault((s => s.Name.ToLower().StartsWith(text.ToLower())));
if (satellite != null)
{
Console.WriteLine("Found satellite: " + satellite);
}
}
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
var textBox = (TextBox) sender;
string text = textBox.Text;
if (!string.IsNullOrWhiteSpace(text))
{
Satellite satellite =
_satellites.FirstOrDefault(
s => s.Numbers1.Any(t => t.StartsWith(text)) || s.Numbers2.Any(t => t.StartsWith(text)));
if (satellite != null)
{
Console.WriteLine("Found satellite: " + satellite);
}
}
}
}
internal class Satellite
{
public string Name { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public List<string> Numbers1 { get; set; }
public List<string> Numbers2 { get; set; }
public override string ToString()
{
return string.Format("Name: {0}", Name);
}
}
}
Result:
If you don't want to use regex you could do something like this:
public List<string> GetSatelliteNames(string input)
{
string[] split = input.split(new string[2] { "\n", "\r\n" });
List<string> result = new List<string>();
foreach (var s in split)
{
string splitagain = s.split(new char[1] { ' ' });
if (s[0] == "0") result.add(s[1]);
}
return result;
}
Related
for background: I have the following code to recursively search for files through a directory, which returns a list of all documents. I want to have the foldername and the documentname.
So far so good. It works well as long as I want to write two elements to my List.
I have a class Companyentry;
class Companyentry
{
public string Entry { get; set; }
public string Folder { get; set; }
public Companyentry(string ey, string fd)
{
Entry = ey;
Folder = fd;
}
}
And my code to write to the List:
List<string> companylist = new List<string>();
private async void button4_Click(object sender, EventArgs e)
{
// ListView initialisierem
listView1.Columns.Add("Dateiname", 200, HorizontalAlignment.Left);
listView1.Columns.Add("Unternehmen", 20, HorizontalAlignment.Left);
listView1.CheckBoxes = true;
listView1.Sorting = SortOrder.Ascending;
DirectoryInfo di = new DirectoryInfo(rootfolder);
Console.WriteLine("No search pattern returns:");
//Write to List
foreach (var fi in di.GetFiles("*", SearchOption.AllDirectories))
{
// Entries
string[] Split = (fi.Directory.Name).Split(new Char[] { '_' });
strEntry = (Split[1]);
companylist.Add(new Companyentry("Entry", "Folder"));
}
I got the following error that "Argument 1 cannot convert from Companyentry to 'string' ":
Issue Screenshot
Whats wrong?
Because this line is wrong:
companylist.Add(new Companyentry("Entry", "Folder"));
Change to this:
companylist.Add("Entry", "Folder");
new Companyentry("Entry", "Folder");
List is a string list.
New to C#, and having trouble finding ways to compare data so far collected from conf file, and outputting it to either text or CSV.
I so far have the skeleton of data extraction code from said conf file, however as I'm new to C# and coding overall, I'm having trouble understanding how to reference that data or compare it.
So far have tried File.WriteAllLiness and defining a variable, but not sure which element to parse, or at which point in the code I should introduce it.
Nothing to hide really, so here's the full output so far:
namespace CompareVal
{
class Program
{
static void Main(string[] args)
{
var lines = File.ReadAllLines(#"D:\*\*\Cleanup\Script Project\Test-Raw-Conf.txt");
var ipAddresses = GetIPAddresses(lines);
var routes = GetRoutes(lines);
var ipRules = GetIPRules(lines);
Console.WriteLine ();
}
static Dictionary<string, string[]> GetIPAddresses(string[] lines)
{
var result = new Dictionary<string, string[]>();
foreach (var line in lines)
{
if (!line.StartsWith("add IPAddress"))
{
continue;
}
Match match;
if (line.Contains("Address=\""))
{
match = Regex.Match(line, "add IPAddress (.*?) Address=\"(.*?)\"");
}
else
{
match = Regex.Match(line, "add IPAddress (.*?) Address=(.*?)$");
}
var name = match.Groups[1].Value;
var value = match.Groups[2].Value;
var items = value.Replace(" ", "").Split(',');
result.Add(name, items);
}
return result;
}
static List<Route> GetRoutes(string[] lines)
{
var result = new List<Route>();
string currentRoutingTable = null;
foreach (var line in lines)
{
if (line.StartsWith("cc RoutingTable"))
{
currentRoutingTable = line.Split(' ')[2].Trim();
}
if (line == "cc .." && currentRoutingTable != null)
{
currentRoutingTable = null;
}
if (line.StartsWith(" add Route"))
{
var #interface = Regex.Match(line, "Interface=(.*?) ").Groups[1].Value;
var gateway = Regex.Match(line, "Gateway=(.*?) ").Groups[1].Value;
var network = Regex.Match(line, "Network=(.*?) ").Groups[1].Value;
result.Add(new Route
{
RoutingTable = currentRoutingTable,
Interface = #interface,
Gateway = gateway,
Network = network
});
}
}
return result;
}
static List<IPRule> GetIPRules(string[] lines)
{
var result = new List<IPRule>();
string currentIPRuleSet = null;
foreach (var line in lines)
{
if (line.StartsWith("cc IPRuleSet"))
{
currentIPRuleSet = line.Split(' ')[2].Trim();
}
if (line == "cc .." && currentIPRuleSet != null)
{
currentIPRuleSet = null;
}
if (line.StartsWith(" add IPRule"))
{
var rule = new IPRule
{
IPRuleSet = currentIPRuleSet,
SourceInterface = GetProperty(line, "SourceInterface"),
DestinationInterface = GetProperty(line, "DestinationInterface"),
};
if (line.Contains("SourceNetwork=\""))
{
rule.SourceNetwork = GetQuotedProperty(line, "SourceNetwork").Replace(" ", "").Split(',');
}
else
{
rule.SourceNetwork = GetProperty(line, "SourceNetwork").Replace(" ", "").Split(',');
}
if (line.Contains("DestinationNetwork=\""))
{
rule.DestinationNetwork = GetQuotedProperty(line, "DestinationNetwork").Replace(" ", "").Split(',');
}
else
{
rule.DestinationNetwork = GetProperty(line, "DestinationNetwork").Replace(" ", "").Split(',');
}
result.Add(rule);
}
}
return result;
}
static string GetProperty(string input, string propertyName)
{
return Regex.Match(input, string.Format("{0}=(.*?) ", propertyName)).Groups[1].Value;
}
static string GetQuotedProperty(string input, string propertyName)
{
return Regex.Match(input, string.Format("{0}=\"(.*?)\" ", propertyName)).Groups[1].Value;
}
class Route
{
public string RoutingTable;
public string Interface;
public string Gateway;
public string Network;
}
class IPRule
{
public string IPRuleSet;
public string SourceInterface;
public string DestinationInterface;
public string[] SourceNetwork;
public string[] DestinationNetwork;
}
}
}
I'm hoping to compare values gathered by IPRule, Route and IPAddress classes, and have a method of outputting each associated value in a list. Each IPAddress is contains a unique string name, but can use any numerical IP address. The idea is to determine when the same IP has been used multiple times, regardless of IPAddress string name, and then compare this to routes, and flag when they are used in IPRules.
For reference, here are some samples of source data:
For IPAddresses, they can be formed in 1 of 2 ways - as a direct IP definition, or as a reference to another IPAddress object (or multi-reference):
add IPAddress Test Address=192.168.1.0/24
IPAddress referencing multiple other IPAddresses:
add IPAddress TestGroup Address="Test1, Test2, Test3"
For routes:
add Route Interface=if5 Gateway=if5_gw Network=Test ProxyARPInterfaces=""
And for IPRules:
add IPRule SourceInterface=if5 DestinationInterface=if3 SourceNetwork=Test1 DestinationNetwork=Test2 Service=dns-all Action=Allow
The above definitions will always follow the same pattern, so the data extraction code has been constructed to expect prefixes to each element, and sort them into their own dictionary or list.
I've got a List of Document
public class Document
{
public string[] fullFilePath;
public bool isPatch;
public string destPath;
public Document() { }
public Document(string[] fullFilePath, bool isPatch, string destPath)
{
this.fullFilePath = fullFilePath;
this.isPatch = isPatch;
this.destPath = destPath;
}
The fullFilepath should a List or an Array of Paths.
For example:
Document 1
---> C:\1.pdf
---> C:\2.pdf
Document 2
---> C:\1.pdf
---> C:\2.pdf
---> C:\3.pdf
etc.
My problem if I am using an array string all Documents got "null" in its fullFilePath.
If I'm using a List for the fullFilePath all Documents got the same entries from the last Document.
Here is how the List is filled:
int docCount = -1;
int i = 0;
List<Document> Documents = new List<Document>();
string[] sourceFiles = new string[1];
foreach (string file in filesCollected)
{
string bc;
string bcValue;
if (Settings.Default.barcodeEngine == "Leadtools")
{
bc = BarcodeReader.ReadBarcodeSymbology(file);
bcValue = "PatchCode";
}
else
{
bc = BarcodeReader.ReadBacrodes(file);
bcValue = "009";
}
if (bc == bcValue)
{
if(Documents.Count > 0)
{
Array.Clear(sourceFiles, 0, sourceFiles.Length);
Array.Resize<string>(ref sourceFiles, 1);
i = 0;
}
sourceFiles[i] = file ;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents.Add(new Document(sourceFiles, true,""));
docCount++;
}
else
{
if (Documents.Count > 0)
{
sourceFiles[i] = file;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents[docCount].fullFilePath = sourceFiles;
}
}
}
You are using the same instance of the array for every document. The instance is updated with a new list of files at every inner loop, but an array is a reference to an area of memory (oversimplification, I know but for the purpose of this answer is enough) and if you change the content of that area of memory you are changing it for every document.
You need to create a new instance of the source files for every new document you add to your documents list. Moreover, when you are not certain of the number of elements that you want to be included in the array, it is a lot better to use a generic List and remove all that code that handles the resizing of the array.
First change the class definition
public class Document
{
public List<string> fullFilePath;
public bool isPatch;
public string destPath;
public Document() { }
public Document(List<string> fullFilePath, bool isPatch, string destPath)
{
this.fullFilePath = fullFilePath;
this.isPatch = isPatch;
this.destPath = destPath;
}
}
And now change your inner loop to
foreach (string file in filesCollected)
{
string bc;
string bcValue;
....
if (bc == bcValue)
{
List<string> files = new List<string>();
files.Add(file);
Documents.Add(new Document(files, true, ""));
docCount++;
}
else
Documents[docCount].fullFilePath.Add(file);
}
Notice that when you need to add a new Document I build a new List<string>, add the current file and pass everything at the constructor (In reality this should be moved directly inside the constructor of the Document class). When you want to add just a new file you could add it directly to the public fullFilePath property
Moving the handling of the files inside the Documents class could be rewritten as
public class Document
{
public List<string> fullFilePath;
public bool isPatch;
public string destPath;
public Document()
{
// Every constructory initializes internally the List
fullFilePath = new List<string>();
}
public Document(string aFile, bool isPatch, string destPath)
{
// Every constructory initializes internally the List
fullFilePath = new List<string>();
this.fullFilePath.Add(aFile);
this.isPatch = isPatch;
this.destPath = destPath;
}
public void AddFile(string aFile)
{
this.fullFilePath.Add(aFile);
}
}
Of course, now in you calling code you pass only the new file or call AddFile without the need to check for the list initialization.
The issue should be here:
string[] sourceFiles = new string[1];
If you move this line of code in your foreach you should solve this problem because in your foreach you always use the same variable, so the same reference.
int docCount = -1;
int i = 0;
List<Document> Documents = new List<Document>();
foreach (string file in filesCollected)
{
string[] sourceFiles = new string[1];
string bc;
string bcValue;
if (Settings.Default.barcodeEngine == "Leadtools")
{
bc = BarcodeReader.ReadBarcodeSymbology(file);
bcValue = "PatchCode";
}
else
{
bc = BarcodeReader.ReadBacrodes(file);
bcValue = "009";
}
if (bc == bcValue)
{
if(Documents.Count > 0)
{
Array.Clear(sourceFiles, 0, sourceFiles.Length);
Array.Resize<string>(ref sourceFiles, 1);
i = 0;
}
sourceFiles[i] = file ;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents.Add(new Document(sourceFiles, true,""));
docCount++;
}
else
{
if (Documents.Count > 0)
{
sourceFiles[i] = file;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents[docCount].fullFilePath = sourceFiles;
}
}
}
I have a flat file that I am reading in C# and then attempting to parse. I mean to store the account number in the flat file in an array.
AccountNumber | AccountName | DateCreated
1 | Bob | 1/1/2011
2 | Donna | 3/2/2013
3 | Jake | 2/21/2010
5 | Sally | 4/2/2014
So far this is what my splitting looks like:
//List<string[]> myArrayList = new List<string[]>();
using (StreamReader read = new StreamReader(#"C:\text\Accounts.txt"))
{
string line;
while ((line = read.ReadLine()) != null)
{
string[] parts = line.Split('|');
Console.WriteLine(parts[0]);
//myArrayList.Add(parts[0]);
}
}
How do I store everything that's printed in parts[0] in it's own array outside of the while loop? I've tried doing a list add but I keep getting errors for invalid arguments. I commented out the bits that don't work.
the following code reads the contents of the file, splits the lines, stores it in a list and finally displays the first column in a RichTextBox
private void button1_Click(object sender, EventArgs e)
{
List<string[]> myArrayList = new List<string[]>();
StreamReader read = new StreamReader(#"C:\test\Accounts.txt");
string line;
while ((line = read.ReadLine()) != null)
{
string[] parts = line.Split('|');
//Console.WriteLine(parts[0]);
myArrayList.Add(parts);
}
foreach (var account in myArrayList)
{
richTextBox1.Text = richTextBox1.Text + account[0].ToString() + Environment.NewLine;
}
}
I like MethodMan's suggestion:
// Class structure
public class Account
{
public int AccountNumber;
public string AccountName;
public DateTime DateCreated;
public Account(string[] info)
{
// This is all dependent that info passed in, is already valid data.
// Otherwise you need to validate it before assigning it
AccountNumber = Convert.ToInt32(info[0]);
AccountName = info[1];
DateCrated = DateTime.Parse(info[2]);
}
}
Your code using the class structure:
List<Account> myAccounts = new List<Account>();
using (StreamReader read = new StreamReader(#"C:\text\Accounts.txt"))
{
string line;
while ((line = read.ReadLine()) != null)
{
string[] parts = line.Split('|');
myAccounts.Add(new Account(parts));
}
}
// Do whatever you want after you have the list filled
I have a log file that I am reading into different objects. One object starts at a Line that contains the words "Announce message" and the following lines contain the data that belongs to that message. This entry stops at a line that contains the word "Disposed".
I want to read all the data from between these 2 lines that, contains certain words.
Im currently using a Dictionary because the line with "Announce message" also contains a UID but the following lines contain the data for that UID.
How would you do that?
This is what i have come up with so far.
public static void P2PLogParser(List<FileInfo> fileList)
{
foreach (FileInfo fi in fileList)
{
//Læser alle linier i csv fil
foreach (var line in File.ReadAllLines(fi.FullName))
{
string MeterUID = GetMeterUID(line);
string MimHashcode = GetMimHashcode(line);
string FirmwareUploadStatus = GetFirmwareUploadStatus(line);
string IsKnown = GetIsKnown(line);
DateTime P2PTimeStamp = GetTimestamp(line);
if (IsMeterEntry(line) && !meters.ContainsKey(MeterUID))
{
string MeterNr = GetMeterUID(line).Replace("4B414D", "");
int meternr = int.Parse(MeterNr, System.Globalization.NumberStyles.HexNumber);
meters.Add(MeterUID, new Meter()
{
MeterUID = MeterUID,
MeterNR = meternr,
P2Pmeterentry = new List<P2PMeterEntry>()
});
}
if (IsMeterEntry(line))
{
P2PMeterEntry p2pmeter = new P2PMeterEntry
{
P2PTimeStamp = P2PTimeStamp,
MimHashcode = MimHashcode,
FirmwareUploadStatus = FirmwareUploadStatus,
IsKnown = IsKnown,
P2PMetersession = new List<P2PMeterSession>()
};
if (IsNoLongerMeterEntry(line))
{
string SessionLevel = GetLevel(line);
string SessionMessage = GetSessionMessage(line);
string Context = GetSessionContext(line);
P2PMeterSession MeterSession = new P2PMeterSession
{
SessionTimeStamp = P2PTimeStamp,
SessionLevel = SessionLevel,
SessionMessage = SessionMessage,
Context = Context
};
meterSession.Add(MeterSession);
}
meters[MeterUID].P2Pmeterentry.Add(p2pmeter);
}
}
}
}
and the IsMeterEntry and IsNoLongerMeterEntry
//IsMeterSession
public static bool IsMeterEntry(string text)
{
return text.ToLower().Contains("announce message received:");
}
public static bool IsNoLongerMeterEntry(string text)
{
return text.ToLower().Contains("context - disposed");
}
Implement a simple state machine with two states: IgnoreLine (initial state) and Announce.
for each line in log
if line contains "Announce message"
read UID
create a StringBuilder
set state=Announce
else if line contains "Disposed"
store the StringBuilder's content in the dictionary[uid]
set state=IgnoreLine
else if state==Announce and line contains "certain words"
append line to StringBuilder