string[] pullspec = File.ReadAllLines(#"C:\fixedlist.txt");
foreach (string ps in pullspec)
{
string pslower = ps.ToLower();
string[] pslowersplit = pslower.Split('|');
var keywords = File.ReadAllLines(#"C:\crawl\keywords.txt");
if (pslower.Contains("|"))
{
if (pslower.Contains(keywords))
{
File.AppendAllText(#"C:\" + keyword + ".txt", pslowersplit[1] + "|" + pslowersplit[0] + "\n");
}
}
}
This doesn't compile because of pslower.Contains(keywords) but I'm not trying to do 100 foreach loops.
Does anybody have any suggestions?
Using LINQ:
if (keywords.Any(k => pslower.Contains(k)))
You have a collection of keywords, and you want to see if any of them (or all of them?) are contained in a given string. I don't see how you would solve this without using a loop somewhere, either explicit or hidden in some function or linq expression.
Another solution - create a String[]of the keywords and then string[] parts = pslower.Split(yourStringArray, StringSplitOptions.None); - if any of your strings appear then parts.Length > 1. You won't easily get your hands on the keywords this way, tho'.
Related
for long time , I always append a string in the following way.
for example if i want to get all the employee names separated by some symbol , in the below example i opeted for pipe symbol.
string final=string.Empty;
foreach(Employee emp in EmployeeList)
{
final+=emp.Name+"|"; // if i want to separate them by pipe symbol
}
at the end i do a substring and remove the last pipe symbol as it is not required
final=final.Substring(0,final.length-1);
Is there any effective way of doing this.
I don't want to appened the pipe symbol for the last item and do a substring again.
Use string.Join() and a Linq projection with Select() instead:
finalString = string.Join("|", EmployeeList.Select( x=> x.Name));
Three reasons why this approach is better:
It is much more concise and readable
– it expresses intend, not how you
want to achieve your goal (in your
case concatenating strings in a
loop). Using a simple projection with Linq also helps here.
It is optimized by the framework for
performance: In most cases string.Join() will
use a StringBuilder internally, so
you are not creating multiple strings that are
then un-referenced and must be
garbage collected. Also see: Do not
concatenate strings inside loops
You don’t have to worry about special cases. string.Join()
automatically handles the case of
the “last item” after which you do
not want another separator, again
this simplifies your code and makes
it less error prone.
I like using the aggregate function in linq, such as:
string[] words = { "one", "two", "three" };
var res = words.Aggregate((current, next) => current + ", " + next);
You should join your strings.
Example (borrowed from MSDN):
using System;
class Sample {
public static void Main() {
String[] val = {"apple", "orange", "grape", "pear"};
String sep = ", ";
String result;
Console.WriteLine("sep = '{0}'", sep);
Console.WriteLine("val[] = {{'{0}' '{1}' '{2}' '{3}'}}", val[0], val[1], val[2], val[3]);
result = String.Join(sep, val, 1, 2);
Console.WriteLine("String.Join(sep, val, 1, 2) = '{0}'", result);
}
}
For building up like this, a StringBuilder is probably a better choice.
For your final pipe issue, simply leave the last append outside of the loop
int size = EmployeeList.length()
for(int i = 0; i < size - 1; i++)
{
final+=EmployeeList.getEmployee(i).Name+"|";
}
final+=EmployeeList.getEmployee(size-1).Name;
I have this code:
System.IO.Directory.CreateDirectory(foldercreationPATH.Text + "\\Tosystem\\" + customersBOX.Text);
Now, if user specifies folder(names) to be created separated by comma, how can I do it?
E.g. if textbox contains "customer1, customer2", then I would like to create separate folders for these.
You would take the string inside the textbox and use the
.split()
method to create an array which you can loop through using a
foreach
loop. I also invoked the
.Trim()
method to remove any trailing white space.
string[] strArr = customersBOX.Text.Split(',');
foreach (string item in strArr)
{
item.Trim();
System.IO.Directory.CreateDirectory(foldercreationPATH.Text + "\\Tosystem\\" + item);
}
you can try this.
var dirs = customersBOX.Text.Split(",".ToArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var dir in dirs)
{
var finalPath = Path.Combine(foldercreationPATH.Text, "Tosystem", dir);
Directory.CreateDirectory(finalPath);
}
I want to check if a string from the first line of a file, is equal with an another string.
The awkward part is that, the strings are the same, but my program doesn't return a true value.
The string is teach and the first line of the file is teach too.
string date = System.IO.File.ReadAllText(folder + "/NPC/" + score_npc + "/" + score_npc + ".txt" );
if (condition)
{
string[] parametrii = date.Split('\n');
if (parametrii[0].Equals("teach"))
//instructions
I tried all the compare methods, i made my own function too. And my function said me that the (parametrii[0])[0] == b
Here is how the file looks like:
teach
poza1
poza2
end
That's propably because new line character is not \n in the file. It may be \r\n instead.
Try File.ReadAllLines instead:
string[] lines = System.IO.File.ReadAllLines(folder + "/NPC/" + score_npc + "/" + score_npc + ".txt" );
if (condition)
{
if (lines[0].Equals("teach"))
// instructions
}
Edit
As Grant Winney suggests, if you only need to manipulate first line (or not all of the) file, you may use File.ReadLines:
string firstLine = File.ReadLines(path).First();
instead.
Have u tried to change
string[] parametrii = date.Split('\n');
into
string[] parametrii = date.Split(Environment.NewLine);?
I suspect it's because your strings contain '\r' character
I have problems splitting this Line. I want to get each String between "#VAR;" and "#ENDVAR;". So at the End, there should be a output of:
Variable=Speed;Value=Fast;
Variable=Fabricator;Value=Freescale;Op==;
Later I will separate each Substring, using ";" as a delimiter but that I guess wont be that hard. This is how a line looks like:
#VAR;Variable=Speed;Value=Fast;Op==;#ENDVAR;#VAR;Variable=Fabricator;Value=Freescale;Op==;#ENDVAR;
I tried some split-options, but most of the time I just get an empty string. I also tried a Regex. But either the Regex was wrong or it wasnt suitable to my String. Probably its wrong, at school we learnt Regex different then its used in C#, so I was confused while implementing.
Regex.Match(t, #"/#VAR([a-z=a-z]*)/#ENDVAR")
Edit:
One small question: I am iterating over many lines like the one in the question. I use NoIdeas code on the line to get it in shape. The next step would be to print it as a Text-File. To print an Array I would have to loop over it. But in every iteration, when I get a new line, I overwrite the Array with the current splitted string. I put the Rest of my code in the question, would be nice if someone could help me.
string[] w ;
foreach (EA.Element theObjects in myPackageObject.Elements)
{
theObjects.Type = "Object";
foreach (EA.Element theElements in PackageHW.Elements)
{
if (theObjects.ClassfierID == theElements.ElementID)
{
t = theObjects.RunState;
w = t.Replace("#ENDVAR;", "#VAR;").Replace("#VAR;", ";").Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in w)
{
tw2.WriteLine(s);
}
}
}
}
The piece with the foreach-loop is wrong pretty sure. I need something to print each splitted t. Thanks in advance.
you can do it without regex using
str.Replace("#ENDVAR;", "#VAR;")
.Split(new string[] { "#VAR;" }, StringSplitOptions.RemoveEmptyEntries);
and if you want to save time you can do:
str.Replace("#ENDVAR;", "#VAR;")
.Replace("#VAR;", ";")
.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
You can use a look ahead assertion here.
#VAR;(.*?)(?=#ENDVAR)
If your string never consists of whitespace between #VAR; and #ENDVAR; you could use the below line, this will not match empty instances of your lines.
#VAR;([^\s]+)(?=#ENDVAR)
See this demo
Answer using raw string manipulation.
IEnumerable<string> StuffFoundInside(string biggerString)
{
var closeDelimeterIndex = 0;
do
{
int openDelimeterIndex = biggerString.IndexOf("#VAR;", startingIndex);
if (openDelimeterIndex != -1)
{
closeDelimeterIndex = biggerString.IndexOf("#ENDVAR;", openDelimeterIndex);
if (closeDelimiterIndex != -1)
{
yield return biggerString.Substring(openDelimeterIndex, closeDelimeterIndex - openDelimiterIndex);
}
}
} while (closeDelimeterIndex != -1);
}
Making a list and adding each item to the list then returning the list might be faster, depending on how the code using this code would work. This allows it to terminate early, but has the coroutine overhead.
Use this regex:
(?i)#VAR;(.+?)#ENDVAR;
Group 1 in each match will be your line content.
(If you don't like regexs)
Code:
var s = "#VAR;Variable=Speed;Value=Fast;Op==;#ENDVAR;#VAR;Variable=Fabricator;Value=Freescale;Op==;#ENDVAR;";
var tokens = s.Split(new String [] {"#ENDVAR;#VAR;"}, StringSplitOptions.None);
foreach (var t in tokens)
{
var st = t.Replace("#VAR;", "").Replace("#ENDVAR;", "");
Console.WriteLine(st);
}
Output:
Variable=Speed;Value=Fast;Op==;
Variable=Fabricator;Value=Freescale;Op==;
Regex.Split works well but yields empty entries that have to be removed as shown here:
string[] result = Regex.Split(input, #"#\w+;")
.Where(s => s != "")
.ToArray();
I tried some split-options, but most of the time I just get an empty string.
In this case the requirements seem to be simpler than you're stating. Simply splitting and using linq will do your whole operation in one statement:
string test = "#VAR;Variable=Speed;Value=Fast;Op==;#ENDVAR;#VAR;Variable=Fabricator;Value=Freescale;Op==;#ENDVAR;";
List<List<string>> strings = (from s in test.Split(new string[]{"#VAR;",";#ENDVAR;"},StringSplitOptions.RemoveEmptyEntries)
let s1 = s.Split(new char[]{';'},StringSplitOptions.RemoveEmptyEntries).ToList<string>()
select (s1)).ToList<List<string>>();
the outpout is:
?strings[0]
Count = 3
[0]: "Variable=Speed"
[1]: "Value=Fast"
[2]: "Op=="
?strings[1]
Count = 3
[0]: "Variable=Fabricator"
[1]: "Value=Freescale"
[2]: "Op=="
To write the data to a file something like this will work:
foreach (List<string> s in strings)
{
System.IO.File.AppendAllLines("textfile1.txt", s);
}
what i'm basically trying to do is compare two HUGE text files and if they match write out a string, i have this written but it's extremely slow. I was hoping you guys might have a better idea. In the below example i'm comparing collect[3] splitfound[0]
string[] collectionlist = File.ReadAllLines(#"C:\found.txt");
string[] foundlist = File.ReadAllLines(#"C:\collection_export.txt");
foreach (string found in foundlist)
{
string[] spltifound = found.Split('|');
string matchfound = spltifound[0].Replace(".txt", ""); ;
foreach (string collect in collectionlist)
{
string[] splitcollect = collect.Split('\\');
string matchcollect = splitcollect[3].Replace(".txt", "");
if (matchcollect == matchfound)
{
end++;
long finaldest = (start - end);
Console.WriteLine(finaldest);
File.AppendAllText(#"C:\copy.txt", "copy \"" + collect + "\" \"C:\\OUT\\" + spltifound[1] + "\\" + spltifound[0] + ".txt\"\n");
break;
}
}
}
Sorry for the vagueness guys,
What I'm trying to do is simply say if content from one file exists in another write out a string(the string isn't important, merely the time to find the two comparatives is). collectionlist is like this:
Apple|Farm
foundlist is like this
C:\cow\horse\turtle.txt
C:\cow\pig\apple.txt
what i'm doing is taking apple from collectionlist, and finding the line that contains apple in foundlist. Then writing out a basic windows copy batch file. Sorry for the confusion.
Answer(All credit to Slaks)
string[] foundlist = File.ReadAllLines(#"C:\found.txt");
var collection = File.ReadLines(#"C:\collection_export.txt")
.ToDictionary(s => s.Split('|')[0].Replace(".txt",""));
using (var writer = new StreamWriter(#"C:\Copy.txt"))
{
foreach (string found in foundlist)
{
string[] splitFound = found.Split('\\');
string matchFound = Path.GetFileNameWithoutExtension(found);
string collectedLine;
if (collection.TryGetValue(matchFound,out collectedLine))
{
string[] collectlinesplit = collectedLine.Split('|');
end++;
long finaldest = (start - end);
Console.WriteLine(finaldest);
writer.WriteLine("copy \"" + found + "\" \"C:\\O\\" + collectlinesplit[1] + "\\" + collectlinesplit[0] + ".txt\"");
}
}
}
Call File.ReadLines() (.NET 4) instead of ReadAllLines() (.NET 2.0).
ReadAllLines needs to build an array to hold the return value, which can be extremely slow for large files.
If you're not using .Net 4.0, replace it with a StreamReader.
Build a Dictionary<string, string> with the matchCollects (once), then loop through the foundList and check whether the HashSet contains matchFound.
This allows you to replace the O(n) inner loop with an O(1) hash check
Use a StreamWriter instead of calling AppendText
EDIT: Call Path.GetFileNameWithoutExtension and the other Path methods instead of manually manipulating strings.
For example:
var collection = File.ReadLines(#"C:\found.txt")
.ToDictionary(s => s.Split('\\')[3].Replace(".txt", ""));
using (var writer = new StreamWriter(#"C:\Copy.txt")) {
foreach (string found in foundlist) {
string splitFound = found.Split('|');
string matchFound = Path.GetFileNameWithoutExtension(found)
string collectedLine;
if (collection.TryGetValue(matchFound, collectedLine)) {
end++;
long finaldest = (start - end);
Console.WriteLine(finaldest);
writer.WriteLine("copy \"" + collectedLine + "\" \"C:\\OUT\\"
+ splitFound[1] + "\\" + spltifound[0] + ".txt\"");
}
}
}
First I'd suggest normalizing both files and putting one of them in a set. This allows you to quickly test whether a specific line is present and reduces the complexity from O(n*n) to O(n).
Also you shouldn't open and close the file every time you write a line:
File.AppendAllText(...); // This causes the file to be opened and closed.
Open the output file once at the start of the operation, write lines to it, then close it when all lines have been written.
You have a cartesian product, so it makes sense to index one side instead of doing an enhaustive linear search.
Extract the keys from one file and use either a Set or SortedList data structure to hold them. This will make the lookups much much faster. (Your overall algorithm will be O(N lg N) instead of O(N**2) )