Priority Operation with parenthesis for my calculator - c#

In my calculator, I would like the notions of operation priorities with parentheses.
I did a unit test to try to solve the problem but I can not make it functional.
UNIT TEST
[Test]
public void Parenthesis_Priority_Case()
{
OperandBase operand = OperandFactory.Create("(1+2)*42");
Assert.IsAssignableFrom<OperandMultiply>(operand);
OperandMultiply multiply = (OperandMultiply)operand;
AssertIsOperandValue(multiply.RightOperand, 42);
AssertIsOperand<OperandAddition>(multiply.LeftOperand, 1, 2);
}
OUTPUT FROM MY UNIT TEST
Expected: assignable from <CalculateLib.Operands.OperandMultiply>
But was: <CalculateLib.Operands.OperandAddition>
at
CalculateTest.OperandFactoryTests.When_Create_
Is_Called.Parenthesis_Priority_Case() in
D:\GIT\Calculate\CalculateTest\OperandFactoryTests
\When_Create_Is_Called.cs:line 79
The code that follows is my factory :
public static class OperandFactory
{
private static Regex parenthesisRegex = new Regex(#"\((?<content>.+)\)$", RegexOptions.Compiled);
public static OperandBase Create(string input)
{
if (HasParenthesisToRemove(input))
{
return Create(GetOperationWithoutParenthesisString(input));
}
bool isValue = decimal.TryParse(input, out decimal outValue);
if (isValue)
{
return new OperandValue
{
Value = outValue
};
}
bool isAddition = input.Contains("+");
if (isAddition)
{
string leftOperand = GetLeftOperandOfAdditionString(input);
string rightOperand = GetRightOperandOfAdditionString(input);
return new OperandAddition()
{
LeftOperand = Create(leftOperand),
RightOperand = Create(rightOperand)
};
}
bool isSubstract = input.Contains("-");
if (isSubstract)
{
string leftOperand = GetLeftOperandOfSubstractString(input);
string rightOperand = GetRightOperandOfSubstractString(input);
return new OperandSubstract()
{
LeftOperand = Create(leftOperand),
RightOperand = Create(rightOperand)
};
}
bool isMultiply = input.Contains("*");
if (isMultiply)
{
string leftOperand = GetLeftOperandOfMultiplyString(input);
string rightOperand = GetRightOperandOfMultiplyString(input);
return new OperandMultiply()
{
LeftOperand = Create(leftOperand),
RightOperand = Create(rightOperand)
};
}
bool isDivide = input.Contains("/");
if (isDivide)
{
string leftOperand = GetLeftOperandOfDivideString(input);
string rightOperand = GetRightOperandOfDivideString(input);
return new OperandDivide()
{
LeftOperand = Create(leftOperand),
RightOperand = Create(rightOperand)
};
}
return null;
}
public static bool HasParenthesisToRemove(string input)
{
if (!IsStartAndEndWithParenthesis(input))
{
return false;
}
if (!HasValueInsideParenthesis(input))
{
return false;
}
string[] groups = GetGroups(input);
return groups.Contains(input);
}
public static string[] GetGroups(string input)
{
const string pattern = #"(?=(\((?>[^()]+|(?<o>)\(|(?<-o>)\))*(?(o)(?!)|)\)))";
IEnumerable<string> result = Regex.Matches(input, pattern).Cast<Match>().Select(x => x.Groups[1].Value);
return result.ToArray();
}
private static bool HasValueInsideParenthesis(string input)
{
if (!parenthesisRegex.IsMatch(input))
{
return false;
}
return true;
}
private static bool IsStartAndEndWithParenthesis(string input)
{
if (!input.Contains("(") && !input.Contains(")"))
{
return false;
}
return true;
}
public static string GetLeftOperandOfDivideString(string input)
{
string[] inputString = input.Split('/');
return inputString[0];
}
public static string GetRightOperandOfDivideString(string input)
{
return input.Substring(GetLeftOperandOfDivideString(input).Length + 1);
}
public static string GetLeftOperandOfMultiplyString(string input)
{
string[] inputString = input.Split('*');
return inputString[0];
}
public static string GetRightOperandOfMultiplyString(string input)
{
return input.Substring(GetLeftOperandOfMultiplyString(input).Length + 1);
}
public static string GetLeftOperandOfSubstractString(string input)
{
string[] inputString = input.Split('-');
return inputString[0];
}
public static string GetRightOperandOfSubstractString(string input)
{
return input.Substring(GetLeftOperandOfSubstractString(input).Length + 1);
}
public static string GetLeftOperandOfAdditionString(string input)
{
string[] inputString = input.Split('+');
return inputString[0];
}
public static string GetRightOperandOfAdditionString(string input)
{
return input.Substring(GetLeftOperandOfAdditionString(input).Length + 1);
}
public static string GetOperationWithoutParenthesisString(string input)
{
var match = parenthesisRegex.Match(input);
if (match.Success)
{
return match.Groups["content"].Value;
}
return null;
}
}
I would like to know if you have any ideas or solutions to this problem?
If you wish to have additional code parts, do not hesitate to ask me
EDIT
The problem is that the priorities are bad with the paretheses. I would like to know where the problem is coming from because I can not identify it.

Related

How to get current CPU and RAM usage, and also how much is available in C# .NET core without looping over all processes?

Is there any method in C# to have the current amount of memory used and how much is available, without needing to loop over all processes and add each workingset64 value?
Well, you could do this:
public class MemoryMetrics
{
public double Total;
public double Used;
public double Free;
}
public class MemoryMetricsService : IMemoryMetricsService
{
public IRuntimeInformationService RuntimeInformationService { get; set; }
public MemoryMetricsService(IRuntimeInformationService runtimeInformationService)
{
this.RuntimeInformationService = runtimeInformationService;
}
public MemoryMetrics GetMetrics()
{
if (RuntimeInformationService.IsUnix())
{
return GetUnixMetrics();
}
return GetWindowsMetrics();
}
private MemoryMetrics GetWindowsMetrics()
{
var output = "";
var info = new ProcessStartInfo();
info.FileName = "wmic";
info.Arguments = "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value";
info.RedirectStandardOutput = true;
using (var process = Process.Start(info))
{
output = process.StandardOutput.ReadToEnd();
}
var lines = output.Trim().Split("\n");
var freeMemoryParts = lines[0].Split("=", StringSplitOptions.RemoveEmptyEntries);
var totalMemoryParts = lines[1].Split("=", StringSplitOptions.RemoveEmptyEntries);
var metrics = new MemoryMetrics();
metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);
metrics.Used = metrics.Total - metrics.Free;
return metrics;
}
private MemoryMetrics GetUnixMetrics()
{
var output = "";
var info = new ProcessStartInfo("free -m");
info.FileName = "/bin/bash";
info.Arguments = "-c \"free -m\"";
info.RedirectStandardOutput = true;
using (var process = Process.Start(info))
{
output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
}
var lines = output.Split("\n");
var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries);
var metrics = new MemoryMetrics();
metrics.Total = double.Parse(memory[1]);
metrics.Used = double.Parse(memory[2]);
metrics.Free = double.Parse(memory[3]);
return metrics;
}
}
as for IRuntimeInformationService:
using System.Runtime.InteropServices;
public class RuntimeInformationService : IRuntimeInformationService
{
public OSPlatform GetOsPlatform()
{
if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return OSPlatform.OSX;
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return OSPlatform.Linux;
if(RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) return OSPlatform.FreeBSD;
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return OSPlatform.Windows;
return OSPlatform.Create("Unknown");
}
public bool IsUnix()
{
var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
return isUnix;
}
public bool IsWindows()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}
public bool IsLinux()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}
public bool IsFreeBSD()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD);
}
public bool IsOSX()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
}
public string GetRuntimeIdentifier()
{
return RuntimeInformation.RuntimeIdentifier;
}
public Architecture GetProcessArchitecture()
{
return RuntimeInformation.ProcessArchitecture;
}
public Architecture GetOSArchitecture()
{
return RuntimeInformation.OSArchitecture;
}
public string GetOSDescription()
{
return RuntimeInformation.OSDescription;
}
public string GetFrameworkDescription()
{
return RuntimeInformation.FrameworkDescription;
}
}

calling methods and arrays objects Library Book console app C#

My professor wants us to create a reusable class and console app that lists book objects. I got the first part of the assignment where I am supposed to print the books I created, but now I am stuck on the part where I have to modify the data and print again using the same method and then check out two books and print again. I have tried to look at example online and although some of them have helped, none have been able to get me to pass this roadblock.
class LibraryBook
{
private string _bookTitle;
private string _authorName;
private string _publisher;
private int _copyrightYear;
private string _callNumber;
public LibraryBook(string booktitle, string authorname, string publisher, int ccyear, string callnumber)
{
BookTitle = booktitle;
AuthorName = authorname;
Publisher = publisher;
CopyrightYear = ccyear;
CallNumber = callnumber;
}
public string BookTitle
{
get
{
return _bookTitle;
}
set
{
_bookTitle = value;
}
}
public string AuthorName
{
get
{
return _authorName;
}
set
{
_authorName = value;
}
}
public string Publisher
{
get
{
return _publisher;
}
set
{
_publisher = value;
}
}
public int CopyrightYear
{
get
{
return _copyrightYear;
}
set
{
const int CYEAR = 2019;
if (value > 0)
_copyrightYear = value;
else
_copyrightYear = CYEAR;
}
}
public string CallNumber
{
get
{
return _callNumber;
}
set
{
_callNumber = value;
}
}
public bool Avail;
public void CheckOut()
{
Avail = true;
}
public void ReturnToShelf()
{
Avail = false;
}
public bool IsCheckedOut()
{
return Avail;
}
public override string ToString()
{
return $"Book Title: {BookTitle}{Environment.NewLine}" +
$"Author Name: {AuthorName}{Environment.NewLine}" +
$"Publisher: {Publisher}{Environment.NewLine}" +
$"Copyright Year: {CopyrightYear}{Environment.NewLine}" +
$"Call Number: {CallNumber}{Environment.NewLine}" +
$"Checked Out: {IsCheckedOut()}{Environment.NewLine}";
}
}
}
class Program
{
static void Main(string[] args)
{
LibraryBook[] favBooksArray = new LibraryBook[5];
favBooksArray[0] = new LibraryBook("Harry Potter and the Philospher's Stone", "J.K. Rowling", "Scholastic Corporation", 1997, "HA-12.36");
favBooksArray[1] = new LibraryBook("Harry Potter and the Chamber of Secret", "J.K. Rowling", "Scholastic Corporation", 2001, "HA-13.48");
favBooksArray[2] = new LibraryBook("Tangerine", "Edward Bloor", "Harcourt", 1997, "TB-58.13");
favBooksArray[3] = new LibraryBook("Roll of Thunder, Hear My Cry", "Mildred D. Taylor", "Dial Press", 1976, "RT-15.22");
favBooksArray[4] = new LibraryBook("The Giver", "Lois Lowry", "Fake Publisher", -1, "Fk200-1");
WriteLine($"------LIBRARY BOOKS------{Environment.NewLine}");
BooksToConsole(favBooksArray);
WriteLine($"------CHANGES MADE----- {Environment.NewLine}");
ChangesToBooks(favBooksArray);
BooksToConsole(favBooksArray);
WriteLine($"------RETURNING BOOKS TO SHELF------{Environment.NewLine}");
ReturnBooksToConsole(favBooksArray);
BooksToConsole(favBooksArray);
}
public static void BooksToConsole(LibraryBook[] favBooksArray)
{
foreach (LibraryBook books in favBooksArray)
{
WriteLine($"{books}{Environment.NewLine}");
}
}
public static void ChangesToBooks(LibraryBook[] favBooksArray)
{
favBooksArray[1].AuthorName = "*****The Rock*****";
favBooksArray[3].BookTitle = "****Totally Not A Fake Name*****";
favBooksArray[1].CheckOut();
favBooksArray[4].CheckOut();
}
public static void ReturnBooksToConsole(LibraryBook[] favBooksArray)
{
favBooksArray[1].ReturnToShelf();
favBooksArray[4].ReturnToShelf();
}
}
}

Create a user node in firebase database Xamarin.Android

I want to create a node in the firebase database like below:
{
"Users" : {
"SktNBDO4pOgS6wNfFIc5lV8p4u73" : {
"Email" : "user#email.com",
"Name" : "Name Surname"
}
}
}
the code I'm using is:
user = auth.CurrentUser;
//Init Firebase
dataBase = FirebaseDatabase.Instance.GetReference("Users").Child(user.Uid).Child("Name");
var postData = new UserListItemViewModel
{
Name = "Name Surname",
Email = "user#email.com",
};
dataBase.SetValue(postData.Name);
what I want to do is to set all the UserListItemViewModel into the database, like:
user = auth.CurrentUser;
//Init Firebase
dataBase = FirebaseDatabase.Instance.GetReference("Users").Child(user.Uid).Child("Name");
Dictionary<string, UserListItemViewModel> userData = new Dictionary<string, UserListItemViewModel>
{
{
user.Uid,
new UserListItemViewModel
{
Name = "Name Surname",
Email = "user#email.com",
}
}
};
dataBase.SetValue(userData);
The problem with the above code is that userData should be Java.Lang.Object.
I came in this solution following a tutorial in Java suggesting
Map<string, UserListItemViewModel> userData = new HashMap(user.Uid, new UserListItemViewModel
{
Name = "Name Surname",
Email = "user#email.com",
})`
Any help please?
I have done similar function with FCM, you can refer to the following codeļ¼š
private DatabaseReference mMsgDatabaseReference;
//************************************
var taskSnapShot = (UploadTask.TaskSnapshot)snapshot;
Android.Net.Uri downloadUrl = taskSnapShot.DownloadUrl;
FriendlyMessage msg = new FriendlyMessage(null,mUserName,downloadUrl.ToString());
mMsgDatabaseReference.Push().SetValue(FriendlyMessage.MsgModelToMap(msg));
Method MsgModelToMap:
public static HashMap MsgModelToMap(FriendlyMessage msg)
{
HashMap map = new HashMap();
map.Put("text", msg.text);
map.Put("name", msg.name);
map.Put("photoUrl", msg.photoUrl);
map.Put("UId", msg.UId);
return map;
}
FriendlyMessage.cs
class FriendlyMessage : Java.Lang.Object, IParcelable
{
public String text;
public String name;
public String photoUrl;
public String UId;
public void setUid(String Id) {
this.UId = Id;
}
public String getUId() {
return UId;
}
private static readonly MyParcelableCreator<FriendlyMessage> _create = new MyParcelableCreator<FriendlyMessage>(GetMessage);
//[ExportField("CREATOR")]
[ExportField("CREATOR")]
public static MyParcelableCreator<FriendlyMessage> Create()
{
return _create;
}
private static FriendlyMessage GetMessage(Parcel parcel)
{
FriendlyMessage msg = new FriendlyMessage();
msg.text = parcel.ReadString();
msg.name = parcel.ReadString();
msg.photoUrl = parcel.ReadString();
msg.UId = parcel.ReadString();
return msg;
}
public FriendlyMessage()
{
}
public FriendlyMessage(String text, String name, String photoUrl)
{
this.text = text;
this.name = name;
this.photoUrl = photoUrl;
this.UId = Guid.NewGuid().ToString();
}
public String getText()
{
return text;
}
public void setText(String text)
{
this.text = text;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getPhotoUrl()
{
return photoUrl;
}
public void setPhotoUrl(String photoUrl)
{
this.photoUrl = photoUrl;
}
public int DescribeContents()
{
throw new NotImplementedException();
}
public void WriteToParcel(Parcel dest, [GeneratedEnum] ParcelableWriteFlags flags)
{
dest.WriteString(text);
dest.WriteString(name);
dest.WriteString(photoUrl);
dest.WriteString(UId);
}
public static HashMap MsgModelToMap(FriendlyMessage msg)
{
HashMap map = new HashMap();
map.Put("text", msg.text);
map.Put("name", msg.name);
map.Put("photoUrl", msg.photoUrl);
map.Put("UId", msg.UId);
return map;
}
public override string ToString()
{
return "name = " + name +" text = " + text + " photoUrl= " + photoUrl+ " UId = " + UId;
}
public static FriendlyMessage MapToMsgModel(DataSnapshot snapShot)
{
FriendlyMessage msg = new FriendlyMessage();
if (snapShot.GetValue(true) == null)
{
return null;
}
msg.UId = snapShot.Key;
msg.text = snapShot.Child("text")?.GetValue(true)?.ToString();
msg.name = snapShot.Child("name")?.GetValue(true)?.ToString();
msg.photoUrl = snapShot.Child("photoUrl")?.GetValue(true)?.ToString();
return msg;
}
public bool Equal_obj(object obj)
{
var message = obj as FriendlyMessage;
return message != null &&
text == message.text &&
name == message.name &&
photoUrl == message.photoUrl &&
UId == message.UId;
}
}

System.Reflection Usage [duplicate]

This question already has answers here:
How to get the list of properties of a class?
(11 answers)
Closed 8 years ago.
I have a class
class ABC
{
Public int one = 10;
Public String two = "123";
public override string ToString()
{
}
}
My question i want to get fields information/values in String of Class "ABC" when ever i will create an object of that class. For example:
Public Class Test
{
public static void Main()
{
ABC a = new ABC();
a.ToString();
}
}
Now here I create an object a of class "ABC", then i want to override method of ToString() to get all fields values of class ABC in a string.
As solution this worked for me :
**Here is an other solution if we use static fields and fieldsInfo:**
class ReflectionTest
{
public static int Height = 2;
public static int Width = 10;
public static int Weight = 12;
public static string Name = "Got It";
public override string ToString()
{
string result = string.Empty;
Type type = typeof(ReflectionTest);
FieldInfo[] fields = type.GetFields();
foreach (var field in fields)
{
string name = field.Name;
object temp = field.GetValue(null);
result += "Name:" + name + ":" + temp.ToString() + System.Environment.NewLine;
}
return result;
}
}
public override string ToString()
{
Dictionary<string, string> fieldValues = new Dictionary<string, string>();
var fields = this.GetType().GetFields();
foreach (var field in fields)
{
fieldValues[field.Name] = field.GetValue(this).ToString();
}
return string.Join(", ", fieldValues.Select(x => string.Format("{0}: {1}", x.Key, x.Value)));
}
You could either use a property to retrieve the string, or override ToString(), both are shown:
public class ABC
{
private Int32 _one = 10;
public Int32 One { get { return _one; } }
private String _two = "123";
public String Two { get { return _two; } }
protected override ToString()
{
return _two;
}
}
not sure if this is what you mean;
public override ToString()
{
return string.Format("one: {1}{0}two: {2}", Environment.NewLine(), one, two);
}
So, here it is:
public class ABC
{
public int one;
public string two;
public int three;
public override string ToString()
{
string names = String.Empty;
System.Reflection.FieldInfo[] infos = this.GetType().GetFields();
foreach (System.Reflection.MemberInfo inf in infos)
{
if (names == String.Empty)
{
names = inf.Name;
}
else
{
names += ';' + inf.Name;
}
}
return names;
}
}
Enjoy!
This should do it:
public override string ToString() {
string s = "";
foreach(FieldInfo f in this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)) {
s += f.Name + "=" + f.GetValue(this).ToString() + "\r\n";
}
return s;
}
BindingFlags.Public reflects only public members. If you want private member too, use also the BindingFlags.Private flag.
You may use the this.GetType().GetFields() at object initialization, to call it only once.
This works for framework 2 also.
Change it to your needs.
Instead of using Reflection, you can use any of the following two approaches:
1: Here you can serialize your class object to a JSON object which would be more readable:
public override string ToString()
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ABC));
string str;
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream, this);
stream.Position = 0;
using (StreamReader streamReader = new StreamReader(stream, Encoding.UTF8))
{
str = streamReader.ReadToEnd();
}
}
return str;
}
2: Here you can serialize your class object to XML which can be utilize some where else:
public override string ToString()
{
XmlSerializer s = new XmlSerializer(typeof(ABC));
StringBuilder sb = new StringBuilder();
var xtw = XmlTextWriter.Create(sb);
s.Serialize
(xtw, this);
return sb.ToString();
}
Finally Get solution to my problem :)
using System;
using System.Reflection;
using System.IO;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main(string[] args)
{
MyClass mC= new MyClass();
string result = mC.ToString();
}
}
class MyClass
{
string someValue = "One";
int someValue1 = -1;
bool someValue2 = false;
float someValue3 = 2.2f;
public string SomeValue
{
get{ return this.someValue;}
}
public int SomeValue1
{
get { return this.someValue1; }
}
public bool SomeValue2
{
get { return this.someValue2; }
}
public float SomeValue3
{
get { return this.someValue3; }
}
public override string ToString()
{
string result = string.Empty;
Type type = this.GetType();
PropertyInfo [] pInfo = type.GetProperties();
for (int i = 0; i <= pInfo.Length-1; i++)
{
Type internalType = this.GetType();
PropertyInfo pInfoObject = internalType.GetProperty(pInfo[i].Name);
object value = pInfoObject.GetValue(this,null);
result += pInfo[i].Name + " : " + value.ToString() + System.Environment.NewLine;
}
return result;
}
}
Here is an other solution if we use static fields and fieldsInfo:
class ReflectionTest
{
public static int Height = 2;
public static int Width = 10;
public static int Weight = 12;
public static string Name = "Got It";
public override string ToString()
{
string result = string.Empty;
Type type = typeof(ReflectionTest);
FieldInfo[] fields = type.GetFields();
foreach (var field in fields)
{
string name = field.Name;
object temp = field.GetValue(null);
result += "Name:" + name + ":" + temp.ToString() + System.Environment.NewLine;
}
return result;
}
}

How to count of sub-string occurrences? [duplicate]

This question already has answers here:
How would you count occurrences of a string (actually a char) within a string?
(34 answers)
Closed 7 years ago.
Suppose I have a string like:
MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com";
then I want to know how many time of occurrences of sub-string "OU=" in this string. With single char, maybe there is something like:
int count = MyString.Split("OU=").Length - 1;
but Split only works for char, not string.
Also how to find the position of n occurrences? For example, the position of 2nd "OU=" in the string?
How to resolve this issue?
Regex.Matches(input, "OU=").Count
You can find all the occurrences and their positions with IndexOf:
string MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com";
string stringToFind = "OU=";
List<int> positions = new List<int>();
int pos = 0;
while ((pos < MyString.Length) && (pos = MyString.IndexOf(stringToFind, pos)) != -1)
{
positions.Add(pos);
pos += stringToFind.Length();
}
Console.WriteLine("{0} occurrences", positions.Count);
foreach (var p in positions)
{
Console.WriteLine(p);
}
You can get the same result from a regular expression:
var matches = Regex.Matches(MyString, "OU=");
Console.WriteLine("{0} occurrences", matches.Count);
foreach (var m in matches)
{
Console.WriteLine(m.Index);
}
The primary differences:
The Regex code is shorter
The Regex code allocates a collection and multiple strings.
The IndexOf code could be written to output the position immediately, without creating a collection.
It's likely that the Regex code will be faster in isolation, but if used many times the combined overhead of the string allocations could cause a much higher load on the garbage collector.
If I were writing this in-line, as something that didn't get used often, I'd probably go with the regex solution. If I were to put it into a library as something to be used a lot, I'd probably go with the IndexOf solution.
this extension needs less resources than regualr expressions.
public static int CountSubstring(this string text, string value)
{
int count = 0, minIndex = text.IndexOf(value, 0);
while (minIndex != -1)
{
minIndex = text.IndexOf(value, minIndex + value.Length);
count++;
}
return count;
}
usage:
MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com";
int count = MyString.CountSubstring("OU=");
(Clippy-mode:ON)
You look like you're parsing an LDAP query!
Would you like to parse it:
manually? Goto "SplittingAndParsing"
Automagically via Win32 calls? Goto "Using Win32 via PInvoke"
(Clippy-mode:OFF)
"SplittingAndParsing":
var MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com";
var chunksAsKvps = MyString
.Split(',')
.Select(chunk =>
{
var bits = chunk.Split('=');
return new KeyValuePair<string,string>(bits[0], bits[1]);
});
var allOUs = chunksAsKvps
.Where(kvp => kvp.Key.Equals("OU", StringComparison.OrdinalIgnoreCase));
"Using Win32 via PInvoke":
Usage:
var parsedDn = Win32LDAP.ParseDN(str);
var allOUs2 = parsedDn
.Where(dn => dn.Key.Equals("OU", StringComparison.OrdinalIgnoreCase));
Utility Code:
// I don't remember where I got this from, honestly...I *think* it came
// from another SO user long ago, but those details I've lost to history...
public class Win32LDAP
{
#region Constants
public const int ERROR_SUCCESS = 0;
public const int ERROR_BUFFER_OVERFLOW = 111;
#endregion Constants
#region DN Parsing
[DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)]
protected static extern int DsGetRdnW(
ref IntPtr ppDN,
ref int pcDN,
out IntPtr ppKey,
out int pcKey,
out IntPtr ppVal,
out int pcVal
);
public static KeyValuePair<string, string> GetName(string distinguishedName)
{
IntPtr pDistinguishedName = Marshal.StringToHGlobalUni(distinguishedName);
try
{
IntPtr pDN = pDistinguishedName, pKey, pVal;
int cDN = distinguishedName.Length, cKey, cVal;
int lastError = DsGetRdnW(ref pDN, ref cDN, out pKey, out cKey, out pVal, out cVal);
if(lastError == ERROR_SUCCESS)
{
string key, value;
if(cKey < 1)
{
key = string.Empty;
}
else
{
key = Marshal.PtrToStringUni(pKey, cKey);
}
if(cVal < 1)
{
value = string.Empty;
}
else
{
value = Marshal.PtrToStringUni(pVal, cVal);
}
return new KeyValuePair<string, string>(key, value);
}
else
{
throw new Win32Exception(lastError);
}
}
finally
{
Marshal.FreeHGlobal(pDistinguishedName);
}
}
public static IEnumerable<KeyValuePair<string, string>> ParseDN(string distinguishedName)
{
List<KeyValuePair<string, string>> components = new List<KeyValuePair<string, string>>();
IntPtr pDistinguishedName = Marshal.StringToHGlobalUni(distinguishedName);
try
{
IntPtr pDN = pDistinguishedName, pKey, pVal;
int cDN = distinguishedName.Length, cKey, cVal;
do
{
int lastError = DsGetRdnW(ref pDN, ref cDN, out pKey, out cKey, out pVal, out cVal);
if(lastError == ERROR_SUCCESS)
{
string key, value;
if(cKey < 0)
{
key = null;
}
else if(cKey == 0)
{
key = string.Empty;
}
else
{
key = Marshal.PtrToStringUni(pKey, cKey);
}
if(cVal < 0)
{
value = null;
}
else if(cVal == 0)
{
value = string.Empty;
}
else
{
value = Marshal.PtrToStringUni(pVal, cVal);
}
components.Add(new KeyValuePair<string, string>(key, value));
pDN = (IntPtr)(pDN.ToInt64() + UnicodeEncoding.CharSize); //skip over comma
cDN--;
}
else
{
throw new Win32Exception(lastError);
}
} while(cDN > 0);
return components;
}
finally
{
Marshal.FreeHGlobal(pDistinguishedName);
}
}
[DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)]
protected static extern int DsQuoteRdnValueW(
int cUnquotedRdnValueLength,
string psUnquotedRdnValue,
ref int pcQuotedRdnValueLength,
IntPtr psQuotedRdnValue
);
public static string QuoteRDN(string rdn)
{
if (rdn == null) return null;
int initialLength = rdn.Length;
int quotedLength = 0;
IntPtr pQuotedRDN = IntPtr.Zero;
int lastError = DsQuoteRdnValueW(initialLength, rdn, ref quotedLength, pQuotedRDN);
switch (lastError)
{
case ERROR_SUCCESS:
{
return string.Empty;
}
case ERROR_BUFFER_OVERFLOW:
{
break; //continue
}
default:
{
throw new Win32Exception(lastError);
}
}
pQuotedRDN = Marshal.AllocHGlobal(quotedLength * UnicodeEncoding.CharSize);
try
{
lastError = DsQuoteRdnValueW(initialLength, rdn, ref quotedLength, pQuotedRDN);
switch(lastError)
{
case ERROR_SUCCESS:
{
return Marshal.PtrToStringUni(pQuotedRDN, quotedLength);
}
default:
{
throw new Win32Exception(lastError);
}
}
}
finally
{
if(pQuotedRDN != IntPtr.Zero)
{
Marshal.FreeHGlobal(pQuotedRDN);
}
}
}
[DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)]
protected static extern int DsUnquoteRdnValueW(
int cQuotedRdnValueLength,
string psQuotedRdnValue,
ref int pcUnquotedRdnValueLength,
IntPtr psUnquotedRdnValue
);
public static string UnquoteRDN(string rdn)
{
if (rdn == null) return null;
int initialLength = rdn.Length;
int unquotedLength = 0;
IntPtr pUnquotedRDN = IntPtr.Zero;
int lastError = DsUnquoteRdnValueW(initialLength, rdn, ref unquotedLength, pUnquotedRDN);
switch (lastError)
{
case ERROR_SUCCESS:
{
return string.Empty;
}
case ERROR_BUFFER_OVERFLOW:
{
break; //continue
}
default:
{
throw new Win32Exception(lastError);
}
}
pUnquotedRDN = Marshal.AllocHGlobal(unquotedLength * UnicodeEncoding.CharSize);
try
{
lastError = DsUnquoteRdnValueW(initialLength, rdn, ref unquotedLength, pUnquotedRDN);
switch(lastError)
{
case ERROR_SUCCESS:
{
return Marshal.PtrToStringUni(pUnquotedRDN, unquotedLength);
}
default:
{
throw new Win32Exception(lastError);
}
}
}
finally
{
if(pUnquotedRDN != IntPtr.Zero)
{
Marshal.FreeHGlobal(pUnquotedRDN);
}
}
}
#endregion DN Parsing
}
public class DNComponent
{
public string Type { get; protected set; }
public string EscapedValue { get; protected set; }
public string UnescapedValue { get; protected set; }
public string WholeComponent { get; protected set; }
public DNComponent(string component, bool isEscaped)
{
string[] tokens = component.Split(new char[] { '=' }, 2);
setup(tokens[0], tokens[1], isEscaped);
}
public DNComponent(string key, string value, bool isEscaped)
{
setup(key, value, isEscaped);
}
private void setup(string key, string value, bool isEscaped)
{
Type = key;
if(isEscaped)
{
EscapedValue = value;
UnescapedValue = Win32LDAP.UnquoteRDN(value);
}
else
{
EscapedValue = Win32LDAP.QuoteRDN(value);
UnescapedValue = value;
}
WholeComponent = Type + "=" + EscapedValue;
}
public override bool Equals(object obj)
{
if (obj is DNComponent)
{
DNComponent dnObj = (DNComponent)obj;
return dnObj.WholeComponent.Equals(this.WholeComponent, StringComparison.CurrentCultureIgnoreCase);
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return WholeComponent.GetHashCode();
}
}
public class DistinguishedName
{
public DNComponent[] Components
{
get
{
return components.ToArray();
}
}
private List<DNComponent> components;
private string cachedDN;
public DistinguishedName(string distinguishedName)
{
cachedDN = distinguishedName;
components = new List<DNComponent>();
foreach (KeyValuePair<string, string> kvp in Win32LDAP.ParseDN(distinguishedName))
{
components.Add(new DNComponent(kvp.Key, kvp.Value, true));
}
}
public DistinguishedName(IEnumerable<DNComponent> dnComponents)
{
components = new List<DNComponent>(dnComponents);
cachedDN = GetWholePath(",");
}
public bool Contains(DNComponent dnComponent)
{
return components.Contains(dnComponent);
}
public string GetDNSDomainName()
{
List<string> dcs = new List<string>();
foreach (DNComponent dnc in components)
{
if(dnc.Type.Equals("DC", StringComparison.CurrentCultureIgnoreCase))
{
dcs.Add(dnc.UnescapedValue);
}
}
return string.Join(".", dcs.ToArray());
}
public string GetDomainDN()
{
List<string> dcs = new List<string>();
foreach (DNComponent dnc in components)
{
if(dnc.Type.Equals("DC", StringComparison.CurrentCultureIgnoreCase))
{
dcs.Add(dnc.WholeComponent);
}
}
return string.Join(",", dcs.ToArray());
}
public string GetWholePath()
{
return GetWholePath(",");
}
public string GetWholePath(string separator)
{
List<string> parts = new List<string>();
foreach (DNComponent component in components)
{
parts.Add(component.WholeComponent);
}
return string.Join(separator, parts.ToArray());
}
public DistinguishedName GetParent()
{
if(components.Count == 1)
{
return null;
}
List<DNComponent> tempList = new List<DNComponent>(components);
tempList.RemoveAt(0);
return new DistinguishedName(tempList);
}
public override bool Equals(object obj)
{
if(obj is DistinguishedName)
{
DistinguishedName objDN = (DistinguishedName)obj;
if (this.Components.Length == objDN.Components.Length)
{
for (int i = 0; i < this.Components.Length; i++)
{
if (!this.Components[i].Equals(objDN.Components[i]))
{
return false;
}
}
return true;
}
return false;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return cachedDN.GetHashCode();
}
}
below should work
MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com";
int count = Regex.Matches(MyString, "OU=").Count
int count = myString.Split(new []{','})
.Count(item => item.StartsWith(
"OU=", StringComparison.OrdinalIgnoreCase))
Here are two examples of how you can get the results that you are looking for
var MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com";
This one you would see a list of the values separated but it would have DC just an idea to
show that the split with String does work`
var split = MyString.Split(new string[] { "OU=", "," }, StringSplitOptions.RemoveEmptyEntries);
This one will Split and return you only the 3 items into a List so that if you don't rely on a count you can visually validate that it returns the 3 Levels of `OU=``
var lstSplit = MyString.Split(new[] { ',' })
.Where(splitItem => splitItem.StartsWith(
"OU=", StringComparison.OrdinalIgnoreCase)).ToList();
public static int CountOccurences(string needle, string haystack)
{
return (haystack.Length - haystack.Replace(needle, "").Length) / needle.Length;
}
Benchmarked it against other answers here (the regex one and the "IndexOf" one), works faster.

Categories