Sorry, this is pretty basic but for the life of me I have not been able to solve it:
I have this:
public static IHtmlString HrefLangLinks(this PageData currentPage)
{
var availablePageLanguages = currentPage.ExistingLanguages.Select(culture => culture.Name).ToArray();
foreach (string listitem in availablePageLanguages)
{
var Output = string.Join(",", listitem);
}
// Dictionary<String, String>
return new HtmlString(Output.ToString());
}
I would like to get the results of the foreach loop outputted in the return value. But Visual Studio informs me that "Output" (the instance in my return value) does not exist in the current context.
I thought I could solve this by adding var Output =""; outside of my foreach loop but that did not work.
Define Output before going into the foreach loop and then assign it a value:
var Output = "";
foreach (string listitem in availablePageLanguages)
{
Output = string.Join(",", listitem);
}
Apart from that I wonder if you really need a for loop in this case as you should also be able to this at once if availablePageLanguages is an array of string (string[]):
var Output = String.Join(" ", availablePageLanguages));
Related
I'd like to get all class name icon from fontawesome to list or array in c# from fontawesome.
I'd like to get all variants icon for example:
fas fa-abacus
far fa-abacus
fal fa-abacus
...
I tried to extract it from the css file, but it only gets the icon names themselves without prefixes.
var text = File.ReadAllText(#"fontawesome\all.css");
var allMatches = Regex.Matches(text, #"^\.fa\-(.*):", RegexOptions.Multiline);
Thank's for help.
Monika
public List<string> ListOfFontAwesomeIcons(string FilePath)
{
List<string> response = new List<string>();
List<string> fontAwesomePrefixes = new { "fas", "far" /*manually add all prefixes*/ }
var textLines = File.ReadAllLines($"{FilePath}");
foreach(string l in textLines)
{
foreach(string p in fontAwesomePrefixes)
{
if(l.Contains(p))
response.Add(l.Replace($"{p} "));
}
}
return response;
}
I ran this in C# 9, VS2019 just based off of feeding it a test string, and it worked for me. I double-checked for fa- in the result list to make sure I excluded all of the other results.
Also, I just converted to List of strings for display. You don't really need to do that, depending on what you're doing with your results.
EDIT: Code updated to reflect FA's .css file available on their website, not the format of the string I was using earlier.
Replace the path in the first line with whatever reflects your project. Note that there are faster methods than ReadAllText, but it should be fine for this.
string text = System.IO.File.ReadAllText("./wwwroot/css/all.css");
var allMatches = Regex.Matches(text, "(?<=[.]).*?(fa-)?.*?(?=[:])", RegexOptions.None);
List<string> allMatchesStrings = new();
foreach (var item in allMatches)
{
if (item.ToString().Contains("fa-"))
allMatchesStrings.Add(item.ToString());
}
foreach (var item in allMatchesStrings)
{
Console.WriteLine(item);
}
I'm building a simple dictionary from a reg file (export from Windows Regedit). The .reg file contains a key in square brackets, followed by zero or more lines of text, followed by a blank line. This code will create the dictionary that I need:
var a = File.ReadLines("test.reg");
var dict = new Dictionary<String, List<String>>();
foreach (var key in a) {
if (key.StartsWith("[HKEY")) {
var iter = a.GetEnumerator();
var value = new List<String>();
do {
iter.MoveNext();
value.Add(iter.Current);
} while (String.IsNullOrWhiteSpace(iter.Current) == false);
dict.Add(key, value);
}
}
I feel like there is a cleaner (prettier?) way to do this in a single Linq statement (using a group by), but it's unclear to me how to implement the iteration of the value items into a list. I suspect I could do the same GetEnumerator in a let statement but it seems like there should be a way to implement this without resorting to an explicit iterator.
Sample data:
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.msu]
#="Microsoft.System.Update.1"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.MTS]
#="WMP11.AssocFile.M2TS"
"Content Type"="video/vnd.dlna.mpeg-tts"
"PerceivedType"="video"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.MTS\OpenWithProgIds]
"WMP11.AssocFile.M2TS"=hex(0):
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.MTS\ShellEx]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.MTS\ShellEx\{BB2E617C-0920-11D1-9A0B-00C04FC2D6C1}]
#="{9DBD2C50-62AD-11D0-B806-00C04FD706EC}"
Update
I'm sorry I need to be more specific. The files am looking at around ~300MB so I took the approach I did to keep the memory footprint down. I'd prefer an approach that doesn't require pulling the entire file into memory.
You can always use Regex:
var dict = new Dictionary<String, List<String>>();
var a = File.ReadAllText(#"test.reg");
var results = Regex.Matches(a, "(\\[[^\\]]+\\])([^\\[]+)\r\n\r\n", RegexOptions.Singleline);
foreach (Match item in results)
{
dict.Add(
item.Groups[1].Value,
item.Groups[2].Value.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList()
);
}
I whipped this out real quick. You might be able to improve the regex pattern.
Instead of using GetEnumerator you can take advantage of TakeWhile and Split methods to break your list into smaller list (each sublist represents one key and its values)
var registryLines = File.ReadLines("test.reg");
Dictionary<string, List<string>> resultKeys = new Dictionary<string, List<string>>();
while (registryLines.Count() > 0)
{
// Take the key and values into a single list
var keyValues = registryLines.TakeWhile(x => !String.IsNullOrWhiteSpace(x)).ToList();
// Adds a new entry to the dictionary using the first value as key and the rest of the list as value
if (keyValues != null && keyValues.Count > 0)
resultKeys.Add(keyValues[0], keyValues.Skip(1).ToList());
// Jumps to the next registry (+1 to skip the blank line)
registryLines = registryLines.Skip(keyValues.Count + 1);
}
EDIT based on your update
Update I'm sorry I need to be more specific. The files am looking at
around ~300MB so I took the approach I did to keep the memory
footprint down. I'd prefer an approach that doesn't require pulling
the entire file into memory.
Well, if you can't read the whole file into memory, it makes no sense to me asking for a LINQ solution. Here is a sample of how you can do it reading line by line (still no need for GetEnumerator)
Dictionary<string, List<string>> resultKeys = new Dictionary<string, List<string>>();
using (StreamReader reader = File.OpenText("test.reg"))
{
List<string> keyAndValues = new List<string>();
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
// Adds key and values to a list until it finds a blank line
if (!string.IsNullOrWhiteSpace(line))
keyAndValues.Add(line);
else
{
// Adds a new entry to the dictionary using the first value as key and the rest of the list as value
if (keyAndValues != null && keyAndValues.Count > 0)
resultKeys.Add(keyAndValues[0], keyAndValues.Skip(1).ToList());
// Starts a new Key collection
keyAndValues = new List<string>();
}
}
}
I think you can use a code like this - if you can use memory -:
var lines = File.ReadAllText(fileName);
var result =
Regex.Matches(lines, #"\[(?<key>HKEY[^]]+)\]\s+(?<value>[^[]+)")
.OfType<Match>()
.ToDictionary(k => k.Groups["key"], v => v.Groups["value"].ToString().Trim('\n', '\r', ' '));
C# Demo
This will take 24.173 seconds for a file with more than 4 million lines - Size:~550MB - by using 1.2 GB memory.
Edit :
The best way is using File.ReadAllLines as it is lazy:
var lines = File.ReadAllLines(fileName);
var keyRegex = new Regex(#"\[(?<key>HKEY[^]]+)\]");
var currentKey = string.Empty;
var currentValue = string.Empty;
var result = new Dictionary<string, string>();
foreach (var line in lines)
{
var match = keyRegex.Match(line);
if (match.Length > 0)
{
if (!string.IsNullOrEmpty(currentKey))
{
result.Add(currentKey, currentValue);
currentValue = string.Empty;
}
currentKey = match.Groups["key"].ToString();
}
else
{
currentValue += line;
}
}
This will take 17093 milliseconds for a file with 795180 lines.
I'm building a PowerShell host by C#, and I want to display the result after invoking PowerShell. Now I use the following method:
public static string GetLogQueriedString(
PSMemberInfoCollection<PSPropertyInfo> PSPropertyCollection)
{
string line = string.Empty;
foreach (var item in PSPropertyCollection)
{
if (!line.Equals(string.Empty)) line += ",";
line += item.Name + " : " + item.Value;
}
return line;
}
It works if the PSObject has many properties that I need, but in this situation, if the PSObject is a string, the result is not what I want. It will display "Length: 40", rather than the string itself.
And another question: if I execute several PowerShell commands, why will it display all the results, including the previous result. For example, I execute "ls; get-process", and it will display the result of "ls" and the result of "get-process".
I think we need to see more of your code. The typical approach to display returned PSObjects is:
using (var ps = PowerShell.Create()) {
while (true) {
Console.WriteLine("Enter an expression:");
string input = Console.ReadLine();
if (String.IsNullOrWhiteSpace(input)) break;
ps.AddScript(input);
Collection<PSObject> results = ps.Invoke();
foreach (var result in results) {
Console.WriteLine(result);
}
}
}
If you don't need to access properties on the returned objects and all you're interested in is the formatted text try changing this line:
ps.AddScript(input + " | Out-String");
If you want to do custom formatting based on object type, you will need to test for the type and format as you see fit:
foreach (var result in results) {
var baseObj = result.BaseObject;
if (baseObj is System.Diagnostics.Process)
{
var p = (System.Diagnostics.Process) baseObj;
Console.WriteLine("Handles:{0}, NPM:{1}, PM:{2}, etc", p.HandleCount, p.NonpagedSystemMemorySize, p.PagedMemorySize);
}
else {
Console.WriteLine(result);
}
}
More of your code is needed, but just a clarification of the previous answer.... It may be helpful to think of PSObject LIKE an array, in that each value is a key-value pair. Because of this, if you try to explicitly cast like ToString, you'll get the object type, much like if you try to cast an array to a string you'll get a memory reference.
An easy solution is to use a foreach. For your code:
foreach(var r in results) {
string toConsole = r.ToString()
}
Console.WriteLine(toConsole);
I have a List and a ListItemCollection and want to check if there have the same elements.
First, I fill the ListItemCollection with Text and Value. (After a SQL Select)
ListItemCollection tempListName = new ListItemCollection();
ListItem temp_ListItem;
if (reader.HasRows)
{
while (reader.Read())
{
temp_ListItem = new ListItem(reader[1].ToString(), reader[0].ToString());
tempListName.Add(temp_ListItem);
}
}
and I have the List
List<string> tempList = new List<string>(ProfileArray);
with some values like {"1","4","5","7"}
now, I want to check, if the tempList have maybe some elements with the same value in tempListName and read the text from the value adn write it in a new list.
Note: Im using asp.net 2.0.
List.FindAll was already available in C# 2.0:
List<string> newList = tempList.FindAll(s => tempListName.FindByText(s) != null);
ListItemCollection.FindByText:
Use the FindByText method to search the collection for a ListItem with
a Text property that equals text specified by the text parameter. This
method performs a case-sensitive and culture-insensitive comparison.
This method does not do partial searches or wildcard searches. If an
item is not found in the collection using this criteria, null is
returned.
Real simple solution that you can customize and optimize as per your needs.
List<string> names = new List<string>(); // This will hold text for matched items found
foreach (ListItem item in tempListName)
{
foreach (string value in tempList)
{
if (value == item.Value)
{
names.Add(item.Text);
}
}
}
So, for a real simple example, consider something like this:
List<string> tempTextList = new List<string>();
while (reader.Read())
{
string val = reader[0].ToString(),
text = reader[1].ToString();
if (tempList.Contains(val)) { tempTextList.Add(text); }
temp_ListItem = new ListItem(text, val);
tempListName.Add(temp_ListItem);
}
Now, just having a listing of the text values doesn't do you much good, so let's improve that a little:
Dictionary<string, string> tempTextList = new Dictionary<string, string>();
while (reader.Read())
{
string val = reader[0].ToString(),
text = reader[1].ToString();
if (tempList.Contains(val)) { tempTextList.Add(val, text); }
temp_ListItem = new ListItem(text, val);
tempListName.Add(temp_ListItem);
}
Now you can actually find the text for a specific value from the dictionary. You might even want to declare that Dictionary<string, string> in a higher scope and use it elsewhere. If you were to declare it at a higher scope, you'd just change one line, this:
Dictionary<string, string> tempTextList = new Dictionary<string, string>();
to this:
tempTextList = new Dictionary<string, string>();
var resultList = new List<string>();
foreach (string listItem in tempList)
foreach (ListItem listNameItem in tempListName)
if (listNameItem.Value.Equals(listItem))
resultList.Add(listNameItem.Text);
Given the (specimen - real markup may be considerably more complicated) markup and constraints listed below, could anyone propose a solution (C#) more effective/efficient than walking the whole tree to retrieve { "##value1##", "##value2##", "##value3##" }, i.e. a list of tokens that are going to be replaced when the markup is actually used.
Note: I have no control over the markup, structure of the markup or format/naming of the tokens that are being replaced.
<markup>
<element1 attributea="blah">##value1##</element1>
<element2>##value2##</element2>
<element3>
<element3point1>##value1##</element3point1>
<element3point2>##value3##</element3point2>
<element3point3>apple</element3point3>
<element3>
<element4>pear</element4>
</markup>
How about:
var keys = new HashSet<string>();
Regex.Replace(input, "##[^#]+##", match => {
keys.Add(match.Value);
return ""; // doesn't matter
});
foreach (string key in keys) {
Console.WriteLine(key);
}
This:
doesn't bother parsing the xml (just string manipulation)
only includes the unique values (no need to return a MatchCollection with the duplicates we don't want)
However, it may build a larger string, so maybe just Matches:
var matches = Regex.Matches(input, "##[^#]+##");
var result = matches.Cast<Match>().Select(m => m.Value).Distinct();
foreach (string s in result) {
Console.WriteLine(s);
}
I wrote a quick prog with your sample, this should do the trick.
class Program
{
//I just copied your stuff to Test.xml
static void Main(string[] args)
{
XDocument doc = XDocument.Load("Test.xml");
var verbs=new Dictionary<string,string>();
//Add the values to replace ehre
verbs.Add("##value3##", "mango");
verbs.Add("##value1##", "potato");
ReplaceStuff(verbs, doc.Root.Elements());
doc.Save("Test2.xml");
}
//A simple replace class
static void ReplaceStuff(Dictionary<string,string> verbs,IEnumerable<XElement> elements)
{
foreach (var e in elements)
{
if (e.Elements().Count() > 0)
ReplaceStuff(verbs, e.Elements() );
else
{
if (verbs.ContainsKey(e.Value.Trim()))
e.Value = verbs[e.Value];
}
}
}
}