WriteLine both expression and the resulting value? - c#

I often need to log or write values of expression and also something that gives context to that. So for example:
WriteLine($"_managedHandlePtr:{_managedHandlePtr}");
WriteLine($"metadata.GetNative(_ptr, handle):{metadata.GetNative(_ptr, handle)}");
Is it possible to get the original expression from an interpolated string? Something like the below in concept. It would be nice if I could eliminate the stringly part of this but get the same output:
LogExpression($"{_managedHandlePtr}");
LogExprsssion($"{metadata.GetNative(_ptr, handle)}");
// Writes the non-interpolated string expression, a colon, then the evaluated string
void LogExpression(FormattableString formattableString)
{
Console.WriteLine(${formattableString.GetExpression()}:{formattableString.ToString()});
}
Output:
_managedHandlePtr:213456
metadata.GetNative(_ptr, handle):0xG5DcS4
It would also be fine if it had to include the notation from the original string:
{_managedHandlePtr}:213456

I don't think you can get much more than the types of the arguments of the FormtableString.
static class Program
{
static void Main(string[] args)
{
Number a = new Number(1.0); // 1.0
Percent b = new Percent(2.0); // 2%
double c = a + b;
Console.WriteLine(Format($"{a} + {b} = {c}"));
// Number + Percent = Double : 1 + 2% = 1.02
}
static string Format(this FormattableString expression, CultureInfo info = null)
{
if (info == null)
{
info = CultureInfo.InvariantCulture;
}
object[] names = expression.GetArguments().Select((arg) => arg.GetType().Name).ToArray();
return $"{string.Format(expression.Format, names)} : {expression.ToString(info)}";
}
}

Related

How to validate or compare string by omitting certain part of it

I have a string as below
"a1/type/xyz/parts"
The part where 'xyz' exists is dynamic and varies accordingly at any size. I want to compare just the two strings are equal discarding the 'xyz' portion exactly.
For example I have string as below
"a1/type/abcd/parts"
Then my comparison has to be successful
I tried with regular expression as below. Though my knowledge on regular expressions is limited and it did not work. Probably something wrong in the way I used.
var regex = #"^[a-zA-Z]{2}/\[a-zA-Z]{16}/\[0-9a-zA-Z]/\[a-z]{5}/$";
var result = Regex.Match("mystring", regex).Success;
Another idea is to get substring of first and last part omitting the unwanted portion and comparing it.
The comparison should be successful by discarding certain portion of the string with effective code.
Comparison successful cases
string1: "a1/type/21412ghh/parts"
string2: "a1/type/eeeee122ghh/parts"
Comparison failure cases:
string1: "a1/type/21412ghh/parts"
string2: "a2/type/eeeee122ghh/parts/mm"
In short "a1/type/abcd/parts" in this part of string the non-bold part is static always.
Honestly, you could do this using regex, and pull apart the string. But you have a specified delimiter, just use String.Split:
bool AreEqualAccordingToMyRules(string input1, string input2)
{
var split1 = input1.Split('/');
var split2 = input2.Split('/');
return split1.Length == split2.Length // strings must have equal number of sections
&& split1[0] == split2[0] // section 1 must match
&& split1[1] == split2[1] // section 2 must match
&& split1[3] == split2[3] // section 4 must match
}
You can try Split (to get parts) and Linq (to exclude 3d one)
using System.Linq;
...
string string1 = "a1/type/xyz/parts";
string string2 = "a1/type/abcd/parts";
bool result = string1
.Split('/') // string1 parts
.Where((v, i) => i != 2) // all except 3d one
.SequenceEqual(string2 // must be equal to
.Split('/') // string2 parts
.Where((v, i) => i != 2)); // except 3d one
Here's a small programm using string functions to compare the parts before and after the middle part:
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(CutOutMiddle("a1/type/21412ghh/parts"));
Console.WriteLine("True: " + CompareNoMiddle("a1/type/21412ghh/parts", "a1/type/21412ghasdasdh/parts"));
Console.WriteLine("False: " + CompareNoMiddle("a1/type/21412ghh/parts", "a2/type/21412ghh/parts/someval"));
Console.WriteLine("False: " + CompareNoMiddle("a1/type/21412ghh/parts", "a1/type/21412ghasdasdh/parts/someappendix"));
}
private static bool CompareNoMiddle(string s1, string s2)
{
var s1CutOut = CutOutMiddle(s1);
var s2CutOut = CutOutMiddle(s2);
return s1CutOut == s2CutOut;
}
private static string CutOutMiddle(string val)
{
var fistSlash = val.IndexOf('/', 0);
var secondSlash = val.IndexOf('/', fistSlash+1);
var thirdSlash = val.IndexOf('/', secondSlash+1);
var firstPart = val.Substring(0, secondSlash);
var secondPart = val.Substring(thirdSlash, val.Length - thirdSlash);
return firstPart + secondPart;
}
}
returns
a1/type/parts
True: True
False: False
False: False
This solution should cover your case, as said by others, if you have a delimiter use it. In the function below you could change int skip for string ignore or something similar and within the comparison loop if(arrayStringOne[i] == ignore) continue;.
public bool Compare(string valueOne, string valueTwo, int skip) {
var delimiterOccuranceOne = valueOne.Count(f => f == '/');
var delimiterOccuranceTwo = valueTwo.Count(f => f == '/');
if(delimiterOccuranceOne == delimiterOccuranceTwo) {
var arrayStringOne = valueOne.Split('/');
var arrayStringTwo = valueTwo.Split('/');
for(int i=0; i < arrayStringOne.Length; ++i) {
if(i == skip) continue; // or instead of an index you could use a string
if(arrayStringOne[i] != arrayStringTwo[i]) {
return false;
}
}
return true;
}
return false;
}
Compare("a1/type/abcd/parts", "a1/type/xyz/parts", 2);

C# code to convert string to Double

I am trying to convert some particular types of strings into double in c#. Normally, Convert.ToDouble() works all great but this one does not always return healthy strings. Which means that input does not always come in format of "4.2". SOmetimes it also comes in form of 4.4.2. Now, i can also not rely on positioning and truncating since it can be 10.11.445 tomorrow?
Any easy and short string manipulation function that I can apply on this scenario?
struct CalifornicatedNumber
{
private string value;
public CalifornicatedNumber(string value)
{
this.value = value;
}
static public implicit operator CalifornicatedNumber(string value)
{
return new CalifornicatedNumber(value);
}
static public implicit operator CalifornicatedNumber(double value)
{
return new CalifornicatedNumber(value.ToString());
}
static public implicit operator double(CalifornicatedNumber calif)
{
return double.Parse(MakeItMakeSense(calif.value));
}
static private string MakeItMakeSense(string calif)
{
if (calif.Count(x => x == '.') > 1)
calif = calif.Substring(0, calif.IndexOf('.', calif.IndexOf('.') + 1));
return calif;
}
}
then...
CalifornicatedNumber califnum;
califnum = "10.11.145";
Console.WriteLine(califnum);
if (califnum > 10) { Console.WriteLine("huzzah");}
califnum = 13.42;
Console.WriteLine(califnum);
if (califnum > 10) { Console.WriteLine("huzzahZah"); }
...this is the most foolish piece of code I have ever written.
After the posted comments I am assuming you would like to take the string 4.4.2 and convert it to double dropping everything after the second . (if found).
A method such as.
public static double ConvertStringToDouble(string inputString)
{
if (inputString.Count(x => x == '.') > 1)
inputString = inputString.Substring(0, inputString.IndexOf('.', inputString.IndexOf('.') + 1));
return double.Parse(inputString);
}
I would do an approach of creating a bunch of strategies for parsing the input text and then iterating through the strategies until a result is found.
First I'd define a tryParseDouble function:
Func<string, double?> tryParseDouble = t =>
{
double value;
if (double.TryParse(t, out value))
{
return value;
}
return null;
};
Then I'd create my list of strategies:
var strategies = new Func<string, double?>[]
{
t =>
{
var parts = t.Split('.');
return parts.Length > 1
? tryParseDouble(String.Join(".", parts.Take(2)))
: null;
},
tryParseDouble,
t => null,
};
And finally I'd get the result:
var text = "4.4.2";
var result =
strategies
.Select(p => p(text))
.Where(v => v != null)
.FirstOrDefault();
The result variable is a double? with the value parsed or a null if none of the strategies work. The final strategy, t => null, is there to be explicit but is not necessary in getting the final null result.
As new strategies are needed to parse different types of input text they can just be added to the list as needed.
I think this will do what you want according to your comments by parsing either the whole string (if no decimal points) or just the first two parts of the sting if there are multiple decimals.
String[] parts = stringVal.Split('.');
double doubleVal;
if (parts.length > 1)
{
doubleVal = Convert.ToDouble(parts[0] + "." + parts[1]);
}
else
{
doubleVale = Convert.ToDouble(stingVal);
}

Insert in regex expression

I have following string:
10-5*tan(40)-cos(0)-40*sin(90);
I have extracted the math functions and calculated their values:
tan(40) = 1.42;
cos(0) = 1;
sin(90) = 0;
I want to insert these values back into the expression string as:
10-5*(1.42)-(1)-40*(0);
Please assist
I would use Regex.Replace and then use a custom MatchEvaluator to convert your values and insert these, check:
http://msdn.microsoft.com/en-us/library/cft8645c(v=vs.110).aspx
Which would look something like:
class Program
{
static string ConvertMathFunc(Match m)
{
Console.WriteLine(m.Groups["mathfunc"]);
Console.WriteLine(m.Groups["argument"]);
double arg;
if (!double.TryParse(m.Groups["argument"].Value, out arg))
throw new Exception(String.Format("Math function argument could not be parsed to double", m.Groups["argument"].Value));
switch (m.Groups["mathfunc"].Value)
{
case "tan": return Math.Tan(arg).ToString();
case "cos": return Math.Cos(arg).ToString();
case "sin": return Math.Sin(arg).ToString();
default:
throw new Exception(String.Format("Unknown math function '{0}'", m.Groups["mathfunc"].Value));
}
}
static void Main(string[] args)
{
string input = "10 - 5 * tan(40) - cos(0) - 40 * sin(90);";
Regex pattern = new Regex(#"(?<mathfunc>(tan|cos|sin))\((?<argument>[0-9]+)\)");
string output = pattern.Replace(input, new MatchEvaluator(Program.ConvertMathFunc));
Console.WriteLine(output);
}
}

compare the characters in two strings

In C#, how do I compare the characters in two strings.
For example, let's say I have these two strings
"bc3231dsc" and "bc3462dsc"
How do I programically figure out the the strings
both start with "bc3" and end with "dsc"?
So the given would be two variables:
var1 = "bc3231dsc";
var2 = "bc3462dsc";
After comparing each characters from var1 to var2, I would want the output to be:
leftMatch = "bc3";
center1 = "231";
center2 = "462";
rightMatch = "dsc";
Conditions:
1. The strings will always be a length of 9 character.
2. The strings are not case sensitive.
The string class has 2 methods (StartsWith and Endwith) that you can use.
After reading your question and the already given answers i think there are some constraints are missing, which are maybe obvious to you, but not to the community. But maybe we can do a little guess work:
You'll have a bunch of string pairs that should be compared.
The two strings in each pair are of the same length or you are only interested by comparing the characters read simultaneously from left to right.
Get some kind of enumeration that tells me where each block starts and how long it is.
Due to the fact, that a string is only a enumeration of chars you could use LINQ here to get an idea of the matching characters like this:
private IEnumerable<bool> CommonChars(string first, string second)
{
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
var charsToCompare = first.Zip(second, (LeftChar, RightChar) => new { LeftChar, RightChar });
var matchingChars = charsToCompare.Select(pair => pair.LeftChar == pair.RightChar);
return matchingChars;
}
With this we can proceed and now find out how long each block of consecutive true and false flags are with this method:
private IEnumerable<Tuple<int, int>> Pack(IEnumerable<bool> source)
{
if (source == null)
throw new ArgumentNullException("source");
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
bool current = iterator.Current;
int index = 0;
int length = 1;
while (iterator.MoveNext())
{
if(current != iterator.Current)
{
yield return Tuple.Create(index, length);
index += length;
length = 0;
}
current = iterator.Current;
length++;
}
yield return Tuple.Create(index, length);
}
}
Currently i don't know if there is an already existing LINQ function that provides the same functionality. As far as i have already read it should be possible with SelectMany() (cause in theory you can accomplish any LINQ task with this method), but as an adhoc implementation the above was easier (for me).
These functions could then be used in a way something like this:
var firstString = "bc3231dsc";
var secondString = "bc3462dsc";
var commonChars = CommonChars(firstString, secondString);
var packs = Pack(commonChars);
foreach (var item in packs)
{
Console.WriteLine("Left side: " + firstString.Substring(item.Item1, item.Item2));
Console.WriteLine("Right side: " + secondString.Substring(item.Item1, item.Item2));
Console.WriteLine();
}
Which would you then give this output:
Left side: bc3
Right side: bc3
Left side: 231
Right side: 462
Left side: dsc
Right side: dsc
The biggest drawback is in someway the usage of Tuple cause it leads to the ugly property names Item1 and Item2 which are far away from being instantly readable. But if it is really wanted you could introduce your own simple class holding two integers and has some rock-solid property names. Also currently the information is lost about if each block is shared by both strings or if they are different. But once again it should be fairly simply to get this information also into the tuple or your own class.
static void Main(string[] args)
{
string test1 = "bc3231dsc";
string tes2 = "bc3462dsc";
string firstmatch = GetMatch(test1, tes2, false);
string lasttmatch = GetMatch(test1, tes2, true);
string center1 = test1.Substring(firstmatch.Length, test1.Length -(firstmatch.Length + lasttmatch.Length)) ;
string center2 = test2.Substring(firstmatch.Length, test1.Length -(firstmatch.Length + lasttmatch.Length)) ;
}
public static string GetMatch(string fist, string second, bool isReverse)
{
if (isReverse)
{
fist = ReverseString(fist);
second = ReverseString(second);
}
StringBuilder builder = new StringBuilder();
char[] ar1 = fist.ToArray();
for (int i = 0; i < ar1.Length; i++)
{
if (fist.Length > i + 1 && ar1[i].Equals(second[i]))
{
builder.Append(ar1[i]);
}
else
{
break;
}
}
if (isReverse)
{
return ReverseString(builder.ToString());
}
return builder.ToString();
}
public static string ReverseString(string s)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
Pseudo code of what you need..
int stringpos = 0
string resultstart = ""
while not end of string (either of the two)
{
if string1.substr(stringpos) == string1.substr(stringpos)
resultstart =resultstart + string1.substr(stringpos)
else
exit while
}
resultstart has you start string.. you can do the same going backwards...
Another solution you can use is Regular Expressions.
Regex re = new Regex("^bc3.*?dsc$");
String first = "bc3231dsc";
if(re.IsMatch(first)) {
//Act accordingly...
}
This gives you more flexibility when matching. The pattern above matches any string that starts in bc3 and ends in dsc with anything between except a linefeed. By changing .*? to \d, you could specify that you only want digits between the two fields. From there, the possibilities are endless.
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
class Sample {
static public void Main(){
string s1 = "bc3231dsc";
string s2 = "bc3462dsc";
List<string> common_str = commonStrings(s1,s2);
foreach ( var s in common_str)
Console.WriteLine(s);
}
static public List<string> commonStrings(string s1, string s2){
int len = s1.Length;
char [] match_chars = new char[len];
for(var i = 0; i < len ; ++i)
match_chars[i] = (Char.ToLower(s1[i])==Char.ToLower(s2[i]))? '#' : '_';
string pat = new String(match_chars);
Regex regex = new Regex("(#+)", RegexOptions.Compiled);
List<string> result = new List<string>();
foreach (Match match in regex.Matches(pat))
result.Add(s1.Substring(match.Index, match.Length));
return result;
}
}
for UPDATE CONDITION
using System;
class Sample {
static public void Main(){
string s1 = "bc3231dsc";
string s2 = "bc3462dsc";
int len = 9;//s1.Length;//cond.1)
int l_pos = 0;
int r_pos = len;
for(int i=0;i<len && Char.ToLower(s1[i])==Char.ToLower(s2[i]);++i){
++l_pos;
}
for(int i=len-1;i>0 && Char.ToLower(s1[i])==Char.ToLower(s2[i]);--i){
--r_pos;
}
string leftMatch = s1.Substring(0,l_pos);
string center1 = s1.Substring(l_pos, r_pos - l_pos);
string center2 = s2.Substring(l_pos, r_pos - l_pos);
string rightMatch = s1.Substring(r_pos);
Console.Write(
"leftMatch = \"{0}\"\n" +
"center1 = \"{1}\"\n" +
"center2 = \"{2}\"\n" +
"rightMatch = \"{3}\"\n",leftMatch, center1, center2, rightMatch);
}
}

print name of the variable in c#

i have a statement
int A = 10,B=6,C=5;
and i want to write a print function such that i pass the int variable to it and
it prints me the variable name and the value.
eg if i call print(A)
it must return "A: 10", and print (B) then it must return "B:6"
in short i want to know how can i access the name of the variable and print it to string in c#. DO i have to use reflection?
After reading the answers
Hi all, thanks for the suggestions provided. I shall try them out, however i wanted to know if it is at all possible in .NET 2.0? Nothing similar to
#define prt(x) std::cout << #x " = '" << x << "'" << std::endl;
macro which is there in C/C++?
The only sensible way to do this would be to use the Expression API; but that changes the code yet further...
static void Main() {
int A = 10, B = 6, C = 5;
Print(() => A);
}
static void Print<T>(Expression<Func<T>> expression) {
Console.WriteLine("{0}={1}",
((MemberExpression)expression.Body).Member.Name,
expression.Compile()());
}
Note: if this is for debugging purposes, be sure to add [Conditional("DEBUG")] to the method, as using a variable in this way changes the nature of the code in subtle ways.
You can use lambda expressions:
static void Main( string[] args ) {
int A = 50, B = 30, C = 17;
Print( () => A );
Print( () => B );
Print( () => C );
}
static void Print<T>( System.Linq.Expressions.Expression<Func<T>> input ) {
System.Linq.Expressions.LambdaExpression lambda = (System.Linq.Expressions.LambdaExpression)input;
System.Linq.Expressions.MemberExpression member = (System.Linq.Expressions.MemberExpression)lambda.Body;
var result = input.Compile()();
Console.WriteLine( "{0}: {1}", member.Member.Name, result );
}
This is not possible without some 'help' from the call site; even reflection does not know about names of local variables.
This is not possible to do with reflection (see Brian and Joel). In general this is not possible simply because you cannot guarantee a named value is being passed to your print function. For instance, I could just as easily do the following
print(42);
print(A + 42);
Neither of these expressions actually has a name. What would you expect to print here?
Another solution (from a closed post):
Inspired by Jon Skeet's post about Null Reference exception handling and suddenly being reminded about projection there is a way to kinda do that.
Here is complete working codez:
public static class ObjectExtensions {
public static string GetVariableName<T>(this T obj) {
System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();
if(objGetTypeGetProperties.Length == 1)
return objGetTypeGetProperties[0].Name;
else
throw new ArgumentException("object must contain one property");
}
}
class Program {
static void Main(string[] args) {
string strName = "sdsd";
Console.WriteLine(new {strName}.GetVariableName());
int intName = 2343;
Console.WriteLine(new { intName }.GetVariableName());
}
}
If you need to support more types than int, use the Expression API but avoid generics and handle the different expression gracefully:
private static string ToDebugOutput(params Expression<Func<object>>[] variables)
{
var sb = new StringBuilder();
foreach (var input in variables)
{
string name;
if (input.Body is UnaryExpression unary && unary.Operand is MemberExpression operand)
{
name = operand.Member.Name;
}
else if (input.Body is MemberExpression member)
{
name = member.Member.Name;
}
else
{
throw new NotSupportedException($"typeof lambda: {input.Body.GetType()}");
}
var result = input.Compile()();
sb.Append($"{name}={result}, ");
}
return sb.ToString();
}
Usage:
string s = "123";
double d = 1.23;
int i2 = 123;
var out2 = ToDebugOutput(() => s, () => d, () => i2);
// out2 = "s=123, d=1.23, i2=123, "

Categories