I have a string which are combination of rules which I have to extract into array. AND condition are seperated by commas while OR move to next array index below are some condtion I am trying
(1 AND 2) AND (3 AND 4) => ["1,2,3,4"]
1 OR 2 => ["1","2"]
(1 OR (2 AND 3)) AND 4 => ["1,4","2,3,4"]
(1 OR 2) OR (3 OR 4) => ["1","2","3","4"]
I have tried the below approach is there a better approach than this.
static void Main(string[] args)
{
string input = "4 AND (1 OR (2 AND 3))";
List<string> output = new List<string>();
string inputTmp = input.Replace("(", "")
.Replace(")", "")
.Replace(" AND ", ",");
if (inputTmp.Contains("OR"))
{
List<string> orOutput = new List<string>();
List<List<string>> cmbOutput = new List<List<string>>();
char splitChar = ' ';
if (input.Contains(")) AND ((")) { inputTmp = input.Replace(")) AND ((", "&"); splitChar = '&'; }
else { if (input.Contains(")) AND ")) { inputTmp = input.Replace(")) AND ", "&"); splitChar = '&'; } }
if (input.Contains(")) OR ((")) { inputTmp = input.Replace(")) OR ((", "|"); splitChar = '|'; }
else { if (input.Contains(")) OR ")) { inputTmp = input.Replace(")) OR ", "|"); splitChar = '|'; } }
if (splitChar != ' ')
{
foreach (var item in inputTmp.Split(splitChar))
{
orOutput.Add(item.Replace("(", "").Replace(")", "").Replace(" AND ", ","));
}
}
else
{
orOutput.Add(input.Replace("(", "").Replace(")", "").Replace(" AND ", ","));
}
foreach (var item in orOutput)
{
List<string> lcOutput = new List<string>();
foreach (var oritem in item.Replace(" OR ", "|").Split('|'))
{
lcOutput.Add(oritem);
}
cmbOutput.Add(lcOutput);
}
if (cmbOutput.Count > 1 && splitChar == '&')
{
for (int i = 0; i < cmbOutput[0].Count; i++)
{
for (int j = 0; j < cmbOutput[1].Count; j++)
{
output.Add(cmbOutput[0][i] + "," + cmbOutput[1][j]);
}
}
}
else
{
foreach (var item in cmbOutput)
{
foreach (var initem in item) { output.Add(initem); }
}
}
}
else
{
output.Add(inputTmp);
}
output.ForEach(o => { Console.WriteLine(o); });
Console.ReadLine();
}
I've created a method that I hope meets your needs. It parses the given expression recursively.
Source code
public static string Parse(string s)
{
return '"' + InnerParse(s).Replace(";", "\",\"") + '"';
}
private static string InnerParse(string s)
{
int pos;
while ((pos = s.IndexOf('(')) != -1)
{
int count = 1;
int nextPos = pos;
while (count != 0)
{
nextPos = s.IndexOfAny(new[] { ')', '(' }, nextPos + 1);
if (nextPos == -1 || nextPos >= s.Length)
throw new ApplicationException(); // Unpaired parentheses
count = s[nextPos] == '(' ? count + 1 : count - 1;
}
s = (pos != 0 ? s.Substring(0, pos - 1) : String.Empty)
+ InnerParse(s.Substring(pos + 1, nextPos - pos - 1)) // Recursion
+ s.Substring(nextPos + 1);
}
string[] operands = s.Split(new[] { "AND", "OR" }, StringSplitOptions.None);
if (operands.Length != 2)
throw new ApplicationException(); // Count of operands != 2
string op1 = operands[0].Trim();
string op2 = operands[1].Trim();
// If operator is OR
if (s.Contains("OR"))
return op1 + ';' + op2;
// If operator is AND
string[] op1s = op1.Split(';');
string[] op2s = op2.Split(';');
string[] ret = new string[op1s.Length * op2s.Length];
int i = 0;
foreach (string s1 in op1s)
foreach (string s2 in op2s)
ret[i++] = s1 + ',' + s2;
return String.Join(";", ret);
}
Usage example
Console.WriteLine(Parse("(1 OR (2 AND 3)) AND 4"));
Restrictions
Two operators are recognized: AND, OR.
Operators are case-sensitive.
Operators have exactly two operands.
Operands cannot contain a double-quote " or a semicolon ;.
Related
So I've finished Huffman compression algorithm, but it will work only if a .txt file doesn't contain , / ;
So I want to ignore only these symbols
What I've got:
Dictionary of a character and its code, separated by comma. Each pair separated by ;
/ at the end of a dictionary (because next symbol is number of added zeros)
Example:
c,1;a,00;t,01;/3
Of course, when I type in file something like "I love dogs, cats", I've got problems:) Like this one: System.FormatException: "String must be exactly one character long."
Here's my code:
Dictionary<char, string> forDecoding = new Dictionary<char, string>();
using (sr = new StreamReader(fileName))
{
string line = sr.ReadToEnd();
string[] lines = line.Split('/');
string[] dict = lines[0].Split(';');
string[] item = null;
foreach (var v in lines[0])
{
encoded.Add(v);
}
count = Convert.ToInt32(lines[1]);
for (int i = 0; i < dict.Length - 1; i++)
{
item = dict[i].Split(',');
forDecoding.Add(Convert.ToChar(item[0]), item[1]);
}
}
Is there any way to modify it in order to see that comma inside like another symbol of input information that has to be encoded?
Try the following:
Dictionary<char, string> forDecoding = new Dictionary<char, string>();
...
private void LoadEncodedData(string filename)
{
//remove existing items
forDecoding.Clear();
using (System.IO.StreamReader sr = new System.IO.StreamReader(filename))
{
int fileLength = 0;
char previousChar = char.MinValue;
char secondPreviousChar = char.MinValue;
char dictKey = char.MinValue;
string dictVal = string.Empty;
bool isDictVal = false;
bool isNextCharEOF = false;
bool isNumberOfZeros = false;
int numberOfAddedZeros = 0;
string numberOfZerosStr = string.Empty;
while (!sr.EndOfStream)
{
//read char and move position
char currentChar = (char)sr.Read();
//read next char without moving position
char nextChar = (char)sr.Peek();
//65535 = EOF
if (nextChar == 65535)
{
//set val
isNextCharEOF = true;
}
if (!isNextCharEOF && !isDictVal && nextChar == ',')
{
//set value
dictKey = currentChar;
}
else if (!isDictVal && previousChar == ',' && currentChar != ',')
{
//start saving chars for dictionary value
dictVal = currentChar.ToString();
//set value
isDictVal = true;
}
else if (isDictVal && currentChar == ';')
{
System.Diagnostics.Debug.WriteLine("dictKey: '" + dictKey.ToString() + "' dictVal: '" + dictVal + "'");
//add to dictionary
forDecoding.Add(dictKey, dictVal);
//re-initialize
dictVal = string.Empty;
//set value
isDictVal = false;
}
else if (isDictVal)
{
//append
dictVal += currentChar.ToString();
}
else if (!isDictVal && secondPreviousChar == ';' && previousChar == '/' && currentChar != ',')
{
if (!isNextCharEOF)
{
//set value
isNumberOfZeros = true;
numberOfZerosStr = currentChar.ToString();
}
else
{
//set value
numberOfZerosStr = currentChar.ToString();
numberOfAddedZeros = 0;
Int32.TryParse(numberOfZerosStr, out numberOfAddedZeros);
System.Diagnostics.Debug.WriteLine(" numberOfAddedZeros: " + numberOfAddedZeros + System.Environment.NewLine);
//set value
isNumberOfZeros = false;
numberOfZerosStr = string.Empty;
}
}
else if (isNumberOfZeros && (isNextCharEOF || nextChar != ','))
{
//append
numberOfZerosStr += currentChar;
numberOfAddedZeros = 0;
Int32.TryParse(numberOfZerosStr, out numberOfAddedZeros);
System.Diagnostics.Debug.WriteLine(" numberOfAddedZeros: " + numberOfAddedZeros + System.Environment.NewLine);
//set value
isNumberOfZeros = false;
numberOfZerosStr = string.Empty;
}
else if (isNumberOfZeros)
{
//append
numberOfZerosStr += currentChar;
}
//set value
secondPreviousChar = previousChar;
previousChar = currentChar;
fileLength += 1; //increment
}
}
}
Example data: c,1;/,00;t,01;/3
I have a problem with string in C#. I get this string from database, and it contains quote signs ("), so my program doesn't read it correctly.
string attributes = databaseFunctions.GetVariationAttributes(produc_id);
My string in the database is
a:3:{s:9:"variation";a:6:{s:4:"name";s:9:"Variation";s:5:"value";s:24:"type a | type b | type c";s:8:"position";s:1:"0";s:10:"is_visible";s:1:"1";s:12:"is_variation";s:1:"1";s:11:"is_taxonomy";s:1:"0";}s:5:"color";a:6:{s:4:"name";s:5:"Color";s:5:"value";s:27:"RED | BLUE | WHITE | ORANGE";s:8:"position";s:1:"1";s:10:"is_visible";s:1:"1";s:12:"is_variation";s:1:"1";s:11:"is_taxonomy";s:1:"0";}s:4:"test";a:6:{s:4:"name";s:4:"TEST";s:5:"value";s:15:"120 | 140 | 160";s:8:"position";s:1:"2";s:10:"is_visible";s:1:"1";s:12:"is_variation";s:1:"0";s:11:"is_taxonomy";s:1:"0";}}
This is actually the Woocommerce product variation attributes. I need to get each attribute, check if it is used for variations, and if yes, get its name and possible values.
Maybe you have any idea how to do it? I'm trying to use substrings and IndexOf functions (Get index of the first and second colon, then get value from between them and use it in a loop)
I will appreciate any of your advice
[EDIT]
Ok, I did it. It's not the prettiest solution, but it works. I post it here, so others may use it in a similar situation
if(databaseFunctions.CheckVariations(variations))
{
string attributes = databaseFunctions.GetVariationAttributes(produc_id);
List<List<string>> parameters = new List<List<string>>();
List<List<string>> values = new List<List<string>>();
int i_1 = 0;
int i_2 = 0;
//First ':'
int c_1 = attributes.IndexOf(':');
//Second ':'
int c_2 = attributes.IndexOf(':', c_1 + 1);
//First 'a' - number of attributes
int a_1 = Convert.ToInt32(attributes.Substring(c_1 + 1, c_2-c_1 -1));
//For each attribute
for (int i = 0; i < a_1; i++)
{
List<string> parameters_of_attribute = new List<string>();
List<string> values_of_attribute = new List<string>();
//First ':'
int ac_1 = attributes.IndexOf(':', c_2 + 1 + i_1);
//Second ':'
int ac_2 = attributes.IndexOf(':', ac_1 + 1);
//First ':' of a
int kc_1 = attributes.IndexOf(':', ac_2 + 1);
//Second ':' of a
int kc_2 = attributes.IndexOf(':', kc_1 + 1);
//Number of parameter-value pairs
int p_v = Convert.ToInt32(attributes.Substring(kc_1 + 1, kc_2 - kc_1 - 1));
//For each parameter-value pair
for (int j = 0; j < p_v; j++)
{
//First '"' of parameter
int pq_1 = attributes.IndexOf('"', kc_2 + 1 + i_2);
//Second '"' of parameter
int pq_2 = attributes.IndexOf('"', pq_1 + 1);
//Name of parameter
string par = attributes.Substring(pq_1 + 1, pq_2 - pq_1 - 1);
//First '"' of value
int vq_1 = attributes.IndexOf('"', pq_2 + 1);
//Second '"' of value
int vq_2 = attributes.IndexOf('"', vq_1 + 1);
//Value of parameter
string val = attributes.Substring(vq_1 + 1, vq_2 - vq_1 - 1);
parameters_of_attribute.Add(par);
values_of_attribute.Add(val);
i_2 = vq_2 - kc_2;
}
parameters.Add(parameters_of_attribute);
values.Add(values_of_attribute);
i_1 = i_2 + kc_2 - c_2;
i_2 = 0;
}
}
Gordon Breuer published code to read PHP's serialized data format using C# at https://gordon-breuer.de/unknown/2011/05/04/php-un-serialize-with-c.html - unfortunately this is not available as a NuGet package (yet!) - it's based off dinosaur code written for .NET Framework 1.0 back in 2001.
I'm repeating the code below for preservation's sake with extra copyright/origin info (Blogs aren't around forever). According to the original SourceForge project's page the code is licensed under the OSI-approved IBM CPL.
/*
* Serializer.cs
* This is the Serializer class for the PHPSerializationLibrary
*
* https://sourceforge.net/projects/csphpserial/
*
* Copyright 2004 Conversive, Inc. Licensed under Common Public License 1.0
*
* Modified for WP7-Silverlight by Gordon Breuer
* https://gordon-breuer.de/unknown/2011/05/04/php-un-serialize-with-c.html
*
* Updated to be thread-safe and correctly reentrant and with C# 7.0 features added for https://stackoverflow.com/questions/58384540/c-sharp-string-with-from-database-cannot-do-interpolation/
*
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Conversive.PHPSerializationLibrary {
public class PhpSerializer
{
//types:
// N = null
// s = string
// i = int
// d = double
// a = array (hashtable)
private static readonly NumberFormatInfo _nfi = new NumberFormatInfo { NumberGroupSeparator = "", NumberDecimalSeparator = "." };
public Encoding StringEncoding { get; }
/// <summary>Whether or not to strip carriage returns from strings when serializing and adding them back in when deserializing</summary>
public Boolean XmlSafe { get; }
public PhpSerializer()
: this( encoding: new UTF8Encoding(), xmlSafe: true )
{
}
public PhpSerializer( Encoding encoding, Boolean xmlSafe )
{
this.StringEncoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
this.XmlSafe = xmlSafe;
}
private class SerializeState
{
public readonly StringBuilder sb = new StringBuilder();
// These collections used for cycle-detection.
public readonly HashSet<Object> seenCollections = new HashSet<Object>();
}
public String Serialize(object obj)
{
SerializeState state = new SerializeState();
this.Serialize(obj, state );
return state.sb.ToString();
}
//Serialize(object obj)
private void Serialize( Object obj, SerializeState state )
{
StringBuilder sb = state.sb;
if (obj == null)
{
sb.Append("N;");
}
else if (obj is string str)
{
if (XmlSafe)
{
str = str.Replace("rn", "n"); //replace rn with n
str = str.Replace("r", "n"); //replace r not followed by n with a single n Should we do this?
}
sb.Append("s:" + StringEncoding.GetByteCount(str) + ":" + str + ";");
}
else if (obj is bool b)
{
sb.Append("b:" + ( b ? "1" : "0") + ";");
}
else if (obj is int objInt)
{
sb.Append("i:" + objInt.ToString(_nfi) + ";");
}
else if (obj is double objDbl)
{
sb.Append("d:" + objDbl.ToString(_nfi) + ";");
}
else if ( (obj is IReadOnlyDictionary<object, object> ) || ( obj is IDictionary<object, object> ) )
{
if (state.seenCollections.Contains(obj))
{
sb.Append("N;");
}
else
{
state.seenCollections.Add(obj);
IEnumerable<KeyValuePair<Object,Object>> asDictEnum = (IEnumerable<KeyValuePair<Object,Object>>)obj;
sb.Append("a:" + asDictEnum.Count() + ":{");
foreach (var entry in asDictEnum)
{
this.Serialize(entry.Key, state);
this.Serialize(entry.Value, state);
}
sb.Append("}");
}
}
else if (obj is IEnumerable<object> enumerable)
{
if (state.seenCollections.Contains( enumerable ) )
{
sb.Append("N;");
}
else
{
state.seenCollections.Add(enumerable);
IReadOnlyList<Object> asList = enumerable as IReadOnlyList<Object>; // T[] / Array<T> implements IReadOnlyList<T> already.
if( asList == null ) asList = enumerable.ToList();
sb.Append("a:" + asList.Count + ":{");
Int32 i = 0;
foreach( Object item in asList )
{
this.Serialize(i, state);
this.Serialize( item, state);
i++;
}
sb.Append("}");
}
}
else
{
throw new SerializationException( "Value could not be serialized." );
}
}
public Object Deserialize(String str)
{
Int32 pos = 0;
return this.Deserialize(str, ref pos );
}
private Object Deserialize( String str, ref Int32 pos )
{
if( String.IsNullOrWhiteSpace( str ) )
return new Object();
int start, end, length;
string stLen;
switch( str[pos] )
{
case 'N':
pos += 2;
return null;
case 'b':
char chBool = str[pos + 2];
pos += 4;
return chBool == '1';
case 'i':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(";", start);
var stInt = str.Substring(start, end - start);
pos += 3 + stInt.Length;
return Int32.Parse(stInt, _nfi);
case 'd':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(";", start);
var stDouble = str.Substring(start, end - start);
pos += 3 + stDouble.Length;
return Double.Parse(stDouble, _nfi);
case 's':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
var bytelen = Int32.Parse(stLen);
length = bytelen;
if ((end + 2 + length) >= str.Length) length = str.Length - 2 - end;
var stRet = str.Substring(end + 2, length);
while (StringEncoding.GetByteCount(stRet) > bytelen)
{
length--;
stRet = str.Substring(end + 2, length);
}
pos += 6 + stLen.Length + length;
if (XmlSafe) stRet = stRet.Replace("n", "rn");
return stRet;
case 'a':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
length = Int32.Parse(stLen);
var htRet = new Dictionary<object, object>(length);
var alRet = new List<object>(length);
pos += 4 + stLen.Length; //a:Len:{
for (int i = 0; i < length; i++)
{
var key = this.Deserialize(str, ref pos);
var val = this.Deserialize(str, ref pos);
if (alRet != null)
{
if (key is int && (int)key == alRet.Count)
alRet.Add(val);
else
alRet = null;
}
htRet[key] = val;
}
pos++;
if( pos < str.Length && str[pos] == ';')
{
pos++;
}
return alRet != null ? (object)alRet : htRet;
default:
return "";
}
}
}
}
When I run this in Linqpad with your input I get this result output:
void Main()
{
const String attribs = #"a:3:{s:9:""variation"";a:6:{s:4:""name"";s:9:""Variation"";s:5:""value"";s:24:""type a | type b | type c"";s:8:""position"";s:1:""0"";s:10:""is_visible"";s:1:""1"";s:12:""is_variation"";s:1:""1"";s:11:""is_taxonomy"";s:1:""0"";}s:5:""color"";a:6:{s:4:""name"";s:5:""Color"";s:5:""value"";s:27:""RED | BLUE | WHITE | ORANGE"";s:8:""position"";s:1:""1"";s:10:""is_visible"";s:1:""1"";s:12:""is_variation"";s:1:""1"";s:11:""is_taxonomy"";s:1:""0"";}s:4:""test"";a:6:{s:4:""name"";s:4:""TEST"";s:5:""value"";s:15:""120 | 140 | 160"";s:8:""position"";s:1:""2"";s:10:""is_visible"";s:1:""1"";s:12:""is_variation"";s:1:""0"";s:11:""is_taxonomy"";s:1:""0"";}}";
PhpSerializer s = new PhpSerializer();
Object result = s.Deserialize( attribs );
result.Dump();
}
Visualized output:
I am a beginner at C#. I am facing a problem while converting a string to a mathematical expression. I have a UI where user can create formula using random formula field. And in another UI user will give input of those formula field.
like for example at first time the formula may be (a+b)^n and another the formula may be ((a+b+c)^n+b).
In my calculation UI for the first time user will give input for a,b,n and for 2nd formula user will give input for a,b,c,n. Can anyone please help me about how to get the result for both of the formula programmatic-ally? Thanks in advance
This is how it should be done:
public class StringToFormula
{
private string[] _operators = { "-", "+", "/", "*","^"};
private Func<double, double, double>[] _operations = {
(a1, a2) => a1 - a2,
(a1, a2) => a1 + a2,
(a1, a2) => a1 / a2,
(a1, a2) => a1 * a2,
(a1, a2) => Math.Pow(a1, a2)
};
public double Eval(string expression)
{
List<string> tokens = getTokens(expression);
Stack<double> operandStack = new Stack<double>();
Stack<string> operatorStack = new Stack<string>();
int tokenIndex = 0;
while (tokenIndex < tokens.Count) {
string token = tokens[tokenIndex];
if (token == "(") {
string subExpr = getSubExpression(tokens, ref tokenIndex);
operandStack.Push(Eval(subExpr));
continue;
}
if (token == ")") {
throw new ArgumentException("Mis-matched parentheses in expression");
}
//If this is an operator
if (Array.IndexOf(_operators, token) >= 0) {
while (operatorStack.Count > 0 && Array.IndexOf(_operators, token) < Array.IndexOf(_operators, operatorStack.Peek())) {
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
operatorStack.Push(token);
} else {
operandStack.Push(double.Parse(token));
}
tokenIndex += 1;
}
while (operatorStack.Count > 0) {
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
return operandStack.Pop();
}
private string getSubExpression(List<string> tokens, ref int index)
{
StringBuilder subExpr = new StringBuilder();
int parenlevels = 1;
index += 1;
while (index < tokens.Count && parenlevels > 0) {
string token = tokens[index];
if (tokens[index] == "(") {
parenlevels += 1;
}
if (tokens[index] == ")") {
parenlevels -= 1;
}
if (parenlevels > 0) {
subExpr.Append(token);
}
index += 1;
}
if ((parenlevels > 0)) {
throw new ArgumentException("Mis-matched parentheses in expression");
}
return subExpr.ToString();
}
private List<string> getTokens(string expression)
{
string operators = "()^*/+-";
List<string> tokens = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in expression.Replace(" ", string.Empty)) {
if (operators.IndexOf(c) >= 0) {
if ((sb.Length > 0)) {
tokens.Add(sb.ToString());
sb.Length = 0;
}
tokens.Add(c);
} else {
sb.Append(c);
}
}
if ((sb.Length > 0)) {
tokens.Add(sb.ToString());
}
return tokens;
}
}
Call the class and method like this:
string formula = "type your formula here"; //or get it from DB
StringToFormula stf = new StringToFormula();
double result = stf.Eval(formula);
There are plenty methods for formula evaluation,
take a look. Just take your input, replace a, b, n chars in your string to values provided by user and resolve equation with one of methods mentioned.
i think this is the solution
Expression e = new Expression("((a+b+c)^n+b)");
e.Evaluate();
string input= "(12 + 4 * 6) * ((2 + 3 * ( 4 + 2 ) ) ( 5 + 12 ))";
string str4 = "(" + input`enter code here`.Replace(" ", "") + ")";
str4 = str4.Replace(")(", ")*(");
while (str4.Contains('('))
{
string sub1 = str4.Substring(str4.LastIndexOf("(") + 1);
string sub = sub1.Substring(0, sub1.IndexOf(")"));
string sub2 = sub;
string str21 = sub2.Replace("^", "~^~").Replace("/", "~/~").Replace("*", "~*~").Replace("+", "~+~").Replace("-", "~-~");
List<string> str31 = str21.Split('~').ToList();
while (str31.Count > 1)
{
while (str31.Contains("*"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "*")
{
val = Convert.ToDouble(str31[i - 1]) * Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("/"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "/")
{
val = Convert.ToDouble(str31[i - 1]) / Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("+"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "+")
{
val = Convert.ToDouble(str31[i - 1]) + Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("-"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "-")
{
val = Convert.ToDouble(str31[i - 1]) - Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
}
str4 = str4.Replace("(" + sub + ")", str31[0].ToString());
}
string sum = str4;
The most structural approach which comes to my mind would be to define a grammar consisting out of operator symbols (which are apparently +,-,*,/ and ^ in your case) and operands; then, if a derivation of the input in the defined grammar exists, the derivation basically is the expression tree which can then be traversed recursively while the operators are directry translated to the actual operations. I admit that the description is a bit vague, but good parsing can be a bit difficult. Perhaps a look at LL parser can help a bit.
convert String To Mathematical Expression
var s3 = "3 - 4 + 5 * 9"
var s4 = NSExpression(format: s3).expressionValue(with: nil, context: nil) as! Double // 44.0
Answer : 44
I need to break on closest space to 30th character of texbox, and I got very good answer for that:
var x = 30;
if (textBox1.Text.Length > x)
{
var index = textBox1.Text.Select((c, i) => new {c, i}).TakeWhile(q => q.i < x).Where(q => q.c == ' ' ).Select(q => q.i).Last();
textBox1.Text = textBox1.Text.Insert(index, Environment.NewLine);
}
Only problem is that I need to exclude from counting characters like "#A", "#B", because they are used for text formatting.
Although perhaps not the cleanest solution. If you simply count on # (or perform a regex to detect patterns) and add that number to x (30) like:
int paramCount = test.Where(c => c == '#').Count();
var index = test.Select((c, i) => new { c, i })
.TakeWhile(q => q.i < x + paramCount)
.Where(q => q.c == ' ')
.Select(q => q.i)
.Last();
edit
In order to make sure your count only counts the first 30 characters (excluding '#'), you can perform an aggregate in advance:
int paramCount = test.Select((c, i) => new { c, i })
.Aggregate(0, (count, s) => s.c == '#' && s.i < x + count ? count + 1 : count);
textBox1.Text.Replace("#A", "").Replace("#B", "")...
You can try the code below.
string sTemp = textBox1.Text.Substring(0, 30);
sTemp = sTemp.Replace(" #A ", "");
sTemp = sTemp.Replace("#A ", "");
sTemp = sTemp.Replace(" #A", "");
sTemp = sTemp.Replace("#A", "");
sTemp = sTemp.Replace(" #B ", "");
sTemp = sTemp.Replace("#B ", "");
sTemp = sTemp.Replace(" #B", "");
sTemp = sTemp.Replace("#B", "");
int numberOfLeak = 30 - sTemp.Length;
var x = 30 + numberOfLeak;
if (textBox1.Text.Length > x)
{
textBox1.Text = textBox1.Text.Insert(x, Environment.NewLine);
}
string oriText = textBox1.Text;//Original text that you input
int charPerLine = 30;//Number of character per line
string sKeyword = "#A|#B";//You can add more template here, the separator is "|"
string[] arrKeyword = sKeyword.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
ArrayList arrListKeyword = new ArrayList();
for (int i = 0; i < arrKeyword.Length; i++)
{
arrListKeyword.Add(" " + arrKeyword[i] + " ");
arrListKeyword.Add(arrKeyword[i] + " ");
arrListKeyword.Add(" " + arrKeyword[i]);
arrListKeyword.Add(arrKeyword[i]);
}
int nextIndex = 0;
while (true)
{
//Check if the sub string after the NewLine has enough length
if (charPerLine < oriText.Substring(nextIndex).Length)
{
string sSubString = oriText.Substring(nextIndex, charPerLine);
//Replace all keywords with the blank
for (int i = 0; i < arrListKeyword.Count; i++)
{
sSubString = sSubString.Replace(arrListKeyword[i].ToString(), "");
}
int numberOfLeak = charPerLine - sSubString.Length;
int newLineIndex = nextIndex + charPerLine + numberOfLeak;//find the index to insert NewLine
oriText = oriText.Insert(newLineIndex, Environment.NewLine);//Insert NewLine
nextIndex = newLineIndex + Environment.NewLine.Length;//Environment.NewLine cost 2 in length
}
else
{
break;
}
}
textBox1.Text = oriText;
When attemptiing to solve the below assignment :
Using the Arithmetic operators ( +,-,*,/) rearrange four fives to equal the number 1 to 10.
Example : 5/5+5-5 =1 ,5/5+5/5=2
I tried in C# without using Linq (I don't know how to proceed further)
public void GetDetails()
{
char[] sym = new char[] { '+', '-', '/', '*' };
int[] AOf5 = new int[] { 5, 5, 5, 5 };
for (int i = 0; i <4; i++)
{
for (int j = 0; j <4; j++)
{
for (int k = 0; k <4; k++)
{
for (int l = 0; l < 4; l++)
{
int result1 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
AOf5[2] + sym[k] + AOf5[3];
int result2 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
AOf5[2] + sym[l] + AOf5[3];
int result3 = AOf5[0] + sym[i] + AOf5[1] +
sym[k] + AOf5[2] + sym[l] + AOf5[3];
....
....
}
}
}
}
}
I am unable to complete it without linq and using linq.Expecting you help.
Applying left-to-right (no precedence), I can get:
1: ((5+5)-5)/5
2:
3: ((5+5)+5)/5
4: ((5*5)-5)/5
5: ((5-5)*5)+5
6: ((5*5)+5)/5
7: ((5+5)/5)+5
8:
9:
10: ((5+5)+5)-5
With (edit: oops - the "no div" stuff was unnecessary):
var operators = new[] {
new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
};
var options = from i in Enumerable.Range(1, 10)
select new {i, op=(
from op1 in operators
let v1 = op1.Func(5,5)
from op2 in operators
let v2 = op2.Func(v1, 5)
from op3 in operators
let v3 = op3.Func(v2,5)
where v3 == i
select "((5" + op1.Name + "5)" + op2.Name + "5)"
+ op3.Name + "5").FirstOrDefault()};
foreach (var opt in options)
{
Console.WriteLine(opt.i + ": " + opt.op);
}
I did it in a primitive way which I am not sure if the answer is correct. It is easier done in a spreadsheet though. Basically I modified linqfying's codes to generate codes.
Here is it:
public static void GetDetails()
{
int ctr = 0;
char[] sym = new char[] { '+', '-', '/', '*' };
string num = "5";
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 4; k++)
{
for (int l = 0; l < 4; l++)
{
ctr++;
string str = num + sym[i] + num + sym[j] + num + sym[k] + num;
Console.WriteLine("res = " + str + "; ");
Console.WriteLine("if(res>=1 && res<=10)");
Console.WriteLine("Console.WriteLine(\"" + str + "\");");
}
}
}
}
//Console.WriteLine("Total:" + ctr.ToString());
}
It generates 256 sets of operations which I output to a text file, copied and pasted them into a new method:
public static void runit()
{
float res = 0;
res = 5+5+5+5;
if (res >= 1 && res <= 10)
Console.WriteLine("5+5+5+5");
res = 5+5+5+5;
if (res >= 1 && res <= 10)
Console.WriteLine("5+5+5+5");
res = 5+5+5+5;
if (res >= 1 && res <= 10)
Console.WriteLine("5+5+5+5");
//......
//......
//......
//......
res = 5*5*5*5;
if (res >= 1 && res <= 10)
Console.WriteLine("5*5*5*5");
}
And run it again which I get 76 non-unqiue operations which fits between 1 and 10.
And 19 unique ones here (left to right operations only):
5*5/5/5
5*5/5+5
5/5*5/5
5/5*5+5
5/5/5+5
5/5+5/5
5/5+5-5
5/5-5+5
5+5*5/5
5+5/5*5
5+5/5/5
5+5/5-5
5+5+5-5
5+5-5/5
5+5-5+5
5-5/5/5
5-5/5+5
5-5+5/5
5-5+5+5
I'm sure someone can come out with something more creative :P
To add:
I realised after matching with Marc's answer, the initial loops didn't cover all permutations, my answers ain't gonna be right. But since I already spent quite some time, I'll let it stay. :P
The only missing cases in Marc's solution are the ones with operation precedence like in: 5/5+5/5. I added them in an union and here is the correct query.
Marc, if you update your answer with the code below (if you think it's correct) i'll delete this answer:
var operators = new[] {
new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
};
var options = from i in Enumerable.Range(1, 10)
select new
{
i,
op = (
from op1 in operators
let v1 = op1.Func(5, 5)
from op2 in operators
let v2 = op2.Func(v1, 5)
from op3 in operators
let v3 = op3.Func(v2, 5)
where v3 == i
select "((5" + op1.Name + "5)" + op2.Name + "5)"
+ op3.Name + "5")
.Union(
//calculate 2 operations (the left and the right one),
//then operate them together.
from op1 in operators
let v1 = op1.Func(5, 5)
from op2 in operators
let v2 = op2.Func(5, 5)
from op3 in operators
let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2)
where v3 == i
select "(5" + op1.Name + "5)" + op2.Name + "(5"
+ op3.Name + "5)"
).FirstOrDefault()
};
foreach (var opt in options)
{
Console.WriteLine(opt.i + ": " + opt.op);
}
EDIT:
A couple words about let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2): this is an awfully working way to avoid divisions by 0 (which can occur, because you can divide by (5-5)).
I am pretty sure you can filter it in a better way but i left it to enphasize that this problem CAN occur.
Assuming you DON'T want to use LINQ, here is an approach to do an implementation. That said it is horribly unoptimized, and I'd recommend a much shorter LINQ implementation over it. (See: Marc Gravell's post.)
using System;
using System.Collections.Generic;
namespace MathIterator
{
class Program
{
static readonly int[] _inputs = new int[] { 5, 5, 5, 5 };
static readonly char[] _operations = new char[] { '+', '-', '*', '/' };
static Dictionary<int, List<string>> _calculations = new Dictionary<int, List<string>>();
static void Main(string[] args)
{
StartPermutation();
PrintResults();
}
static void StartPermutation()
{
if (_inputs.Length > 0)
Permute(1 /*index*/, _inputs[0], _inputs[0].ToString());
}
static void Permute(int index, int result, string computation)
{
if (index == _inputs.Length)
{
if (!_calculations.ContainsKey(result))
{
_calculations[result] = new List<string>();
}
_calculations[result].Add(computation);
}
else
{
foreach (char operation in _operations)
{
string nextComputation = String.Format("({0} {1} {2})",computation, operation, _inputs[index]);
int nextResult = result;
switch (operation)
{
case '+':
nextResult += _inputs[index];
break;
case '-':
nextResult -= _inputs[index];
break;
case '*':
nextResult *= _inputs[index];
break;
case '/':
nextResult /= _inputs[index];
break;
}
Permute(
index + 1,
nextResult,
nextComputation);
}
}
}
static void PrintResults()
{
for (int i = 1; i <= 10; ++i)
{
if (_calculations.ContainsKey(i))
{
Console.WriteLine("Found {0} entries for key {1}", _calculations[i].Count, i);
foreach (string calculation in _calculations[i])
{
Console.WriteLine(i + " = " + calculation);
}
}
else
{
Console.WriteLine("No entry for key: " + i);
}
}
}
}
}
Here is another implementation. This one follows order of precedence. Again, I do not recommend solving it like this. Even more-so now given the wide dash hacks (to distinguish them from minus signs), but it does seem to work.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace MathIterator
{
class Program
{
static readonly int[] _inputs = new[] { 5, 5, 5, 5 };
//HUGE hack, the '–' is a wide dash NOT a hyphen.
static readonly char[][] _operationLevels = new[] { new[] { '*', '/' }, new[] { '+', '–' } };
static List<string> _calculations = new List<string>();
static Dictionary<int, List<string>> _results = new Dictionary<int, List<string>>();
static void Main(string[] args)
{
StartPermutation();
StartEvaluateCalculations();
PrintResults();
}
static void StartPermutation()
{
if (_inputs.Length > 0)
Permute(1 /*index*/, _inputs[0].ToString());
}
static void Permute(int index, string computation)
{
if (index == _inputs.Length)
{
_calculations.Add(computation);
}
else
{
foreach (char[] operationLevel in _operationLevels)
{
foreach (char operation in operationLevel)
{
string nextComputation = String.Format("{0} {1} {2}", computation, operation, _inputs[index]);
Permute(
index + 1,
nextComputation);
}
}
}
}
static void StartEvaluateCalculations()
{
foreach (string calculation in _calculations)
{
int? result = EvaluateCalculation(calculation);
if (result != null)
{
int intResult = (int) result;
if (!_results.ContainsKey(intResult))
{
_results[intResult] = new List<string>();
}
_results[intResult].Add(calculation);
}
}
}
static int? EvaluateCalculation(string calculation)
{
foreach (char[] operationLevel in _operationLevels)
{
string[] results = calculation.Split(operationLevel, 2);
if (results.Length == 2)
{
int hitIndex = results[0].Length;
Regex firstDigit = new Regex(#"^ -?\d+");
Regex lastDigit = new Regex(#"-?\d+ $");
string firstMatch = lastDigit.Match(results[0]).Value;
int arg1 = int.Parse(firstMatch);
string lastMatch = firstDigit.Match(results[1]).Value;
int arg2 = int.Parse(lastMatch);
int result = 0;
switch (calculation[hitIndex])
{
case '+':
result = arg1 + arg2;
break;
//HUGE hack, the '–' is a wide dash NOT a hyphen.
case '–':
result = arg1 - arg2;
break;
case '*':
result = arg1 * arg2;
break;
case '/':
if ((arg2 != 0) && ((arg1 % arg2) == 0))
{
result = arg1 / arg2;
break;
}
else
{
return null;
}
}
string prePiece = calculation.Remove(hitIndex - 1 - arg1.ToString().Length);
string postPiece = calculation.Substring(hitIndex + 1 + lastMatch.ToLower().Length);
string nextCalculation = prePiece + result + postPiece;
return EvaluateCalculation(nextCalculation);
}
}
return int.Parse(calculation);
}
static void PrintResults()
{
for (int i = 1; i <= 10; ++i)
{
if (_results.ContainsKey(i))
{
Console.WriteLine("Found {0} entries for key {1}", _results[i].Count, i);
foreach (string calculation in _results[i])
{
Console.WriteLine(i + " = " + calculation);
}
}
else
{
Console.WriteLine("No entry for key: " + i);
}
}
}
}
}
Here's a solution which is completely LINQ based (method-syntax) and late-evaluating, which handles all permutations (not only left-to-righ):
static void Main()
{
var solution = PermuteLength(4)
.Where(p => Decimal.Floor(p.Value) == p.Value)
.Where(p => p.Value <= 10 && p.Value >= 0)
.OrderBy(p => p.Value);
foreach (var p in solution)
{
Console.WriteLine(p.Formula + " = " + p.Value);
}
}
public static Operator[] Operators = new[]
{
new Operator {Format = "({0} + {1})", Function = (x, y) => x + y},
new Operator {Format = "({0} - {1})", Function = (x, y) => x - y},
new Operator {Format = "({1} - {0})", Function = (x, y) => y - x},
new Operator {Format = "({0} * {1})", Function = (x, y) => x * y},
new Operator {Format = "({0} / {1})", Function = (x, y) => y == 0 ? 0 : x / y},
new Operator {Format = "({1} / {0})", Function = (x, y) => x == 0 ? 0 : y / x},
};
public static IEnumerable<Permutation> BasePermutation = new[] { new Permutation {Formula = "5", Value = 5m} };
private static IEnumerable<Permutation> PermuteLength(int length)
{
if (length <= 1)
return BasePermutation;
var result = Enumerable.Empty<Permutation>();
for (int i = 1; i <= length / 2; i++)
result = result.Concat(Permute(PermuteLength(i), PermuteLength(length - i)));
return result;
}
private static IEnumerable<Permutation> Permute(IEnumerable<Permutation> left, IEnumerable<Permutation> right)
{
IEnumerable<IEnumerable<IEnumerable<Permutation>>> product = left.Select(l => right.Select(r => ApplyOperators(l, r)));
var aggregate =
product.Aggregate(Enumerable.Empty<IEnumerable<Permutation>>(), (result, item) => result.Concat(item)).
Aggregate(Enumerable.Empty<Permutation>(), (result, item) => result.Concat(item));
return aggregate;
}
private static IEnumerable<Permutation> ApplyOperators(Permutation left, Permutation right)
{
return Operators.Select(o => new Permutation
{
Formula = string.Format(o.Format, left.Formula, right.Formula),
Value = o.Function(left.Value, right.Value)
});
}
public struct Permutation
{
public string Formula;
public decimal Value;
}
public struct Operator
{
public string Format;
public Func<decimal, decimal, decimal> Function;
}
Known problems:
Some solutions are duplicate,
Doesn't handle division-by-zero very well, so some wrong answers (I've assumed anything divided by zero = 0)
Edit:
A part of result:
((5 / 5) / (5 / 5)) = 1
((5 / 5) + (5 / 5)) = 2
((5 + (5 + 5)) / 5) = 3
(5 - ((5 + 5) / 5)) = 3
(((5 * 5) - 5) / 5) = 4
(5 + (5 * (5 - 5))) = 5
(5 - (5 * (5 - 5))) = 5
(5 + ((5 - 5) / 5)) = 5
(5 - ((5 - 5) / 5)) = 5