C# Split ignore commas in input string - c#

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

Related

string with quotes from database, cannot do interpolation

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:

Identifing number of character/digits/special character in string

I want to calculate the summary of string in terms of number of alphabets, digits and special character in C#. For example:
String abc123$% should have summary like A3D3S2 (which means 3 Alphabet, 3 Digits and 2 Special character)
a34=$# should have summary like A1D2S3 (which means 1 Alphabet, 2 Digits and 3 Special character)
a3b$s should have summary like A1D1A1S1A1 (which means 1 Alphabet, 1 Digits,1 Alphabet, 1 Special character,1 Alphabet)
Can anyone guide me how can write an algorithm which can perform the above task in a quick way? as I think if I search the string character by character, then it will take considerable amount of time. and I have a large dataset of strings.
This works:
static string GetSummary(string input)
{
var sb = new StringBuilder();
string prevMode = "";
string curMode = "";
int sameModeCount = 0;
for (int i = 0; i <= input.Length; ++i)
{
if (i < input.Length)
{
char c = input[i];
if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z')
{
curMode = "A";
}
else if ('0' <= c && c <= '9')
{
curMode = "D";
}
else
{
curMode = "S";
}
}
else
{
curMode = "";
}
if (curMode != prevMode && prevMode != "")
{
sb.Append(prevMode);
sb.Append(sameModeCount);
sameModeCount = 0;
}
prevMode = curMode;
++sameModeCount;
}
return sb.ToString();
}
Test:
public static void Main()
{
Console.WriteLine(GetSummary("abc123$%"));
Console.WriteLine(GetSummary("a34=$#"));
Console.WriteLine(GetSummary("a3b$s"));
}
Results:
A3D3S2
A1D2S3
A1D1A1S1A1
With Linq, you can do like this :
string myinput = "abc123$%";
int letter =0 , digit = 0, specialCharacter = 0;
myinput.ToCharArray().ToList().ForEach(x =>
{
letter = Char.IsLetter(x) ? ++letter : letter;
digit = Char.IsDigit(x) ? ++digit : digit;
specialCharacter = !Char.IsLetterOrDigit(x) ?
++specialCharacter : specialCharacter;
});
string formattedVal = String.Format("A{0}D{1}S{2}", letter, digit,
specialCharacter);
You can directly use array in Linq ForEach without converting to list by :
Array.ForEach(myinput.ToCharArray(), x =>
{
letter = Char.IsLetter(x) ? ++letter : letter;
digit = Char.IsDigit(x) ? ++digit : digit;
specialCharacter = !Char.IsLetterOrDigit(x) ? ++specialCharacter : specialCharacter;
});
string formattedVal = String.Format("A{0}D{1}S{2}", letter, digit, specialCharacter);
This should work:
string s = "a3b$s";
char etype = 'X'; //current character's type
char etypeinit = 'X'; //tracker variable - holds type of last character
string str = "";
int count = 1;
foreach(char c in s)
{
//Use this block of conditionals to assign type for current character
if(char.IsLetter(c))
{
etype = 'A';
}
else if(char.IsDigit(c))
{
etype = 'D';
}
else
{
etype = 'S';
}
//This is a different type of character compared to the previous one
if(etypeinit != etype)
{
str += string.Format("{0}{1}",etype,count); //Build the string
count = 1; //Reset count
}
else
{
count++; //Increment because this is the same type as previous one
}
etypeinit = etype; //Set tracker variable to type of current character
}
Console.WriteLine(str);
Little late and little complex but able to produces all expected output as per given inputs in the question, please take a look:
string inputString = "abc123$%ab12";
var results = inputString.Select(x => char.IsLetter(x) ? 'A' :
char.IsDigit(x) ? 'D' : 'S');
StringBuilder outPutBuilder = new StringBuilder();
char previousChar = results.First();
int charCount = 0;
foreach (var item in results)
{
switch (item)
{
case 'A':
if (previousChar == 'A')
{
charCount++;
}
else
{
outPutBuilder.Append(previousChar.ToString() + charCount);
charCount = 1;
}
break;
case 'D':
if (previousChar == 'D')
charCount++;
else
{
outPutBuilder.Append(previousChar.ToString() + charCount);
charCount = 1;
}
break;
default:
if (previousChar == 'S')
charCount++;
else
{
outPutBuilder.Append(previousChar.ToString() + charCount);
charCount = 1;
}
break;
}
previousChar = item;
}
outPutBuilder.Append(previousChar.ToString() + charCount);
Working example
Use a FOR loop to go through each character. If the character is in the range of a-z or A-Z then it is an alphabet. If in the range of 0-9 then it is a digit else special character.
Code
string inputStr = "a3b$s";
string outputStr = string.Empty;
char firstChar = Convert.ToChar(inputStr.Substring(0, 1));
outputStr = char.IsLetter(firstChar) ? "A1" : char.IsDigit(firstChar) ? "D1" : "S1";
for (int i = 1; i < inputStr.Length; i++)
{
char nextChar = char.IsLetter(inputStr[i]) ? 'A' :
char.IsDigit(inputStr[i]) ? 'D' : 'S';
char prevChar = Convert.ToChar(outputStr.Substring(outputStr.Length - 2, 1));
if (nextChar == prevChar)
{
int lastDig = Convert.ToInt32(outputStr.Substring(outputStr.Length - 1, 1));
outputStr = outputStr.Substring(0, outputStr.Length - 1) +
(lastDig + 1).ToString();
}
else
outputStr += nextChar.ToString() + "1";
}
Console.WriteLine(outputStr.ToString());
Output
A1D1A1S1A1
Find demo here

How to convert int to a decimal with comma?

Console.Write("Hoeveel worpen wil je simuleren: ");
int worpen = int.Parse(Console.ReadLine());
Random r = new Random(worpen);
int willekeur = r.Next(1, worpen);
double willekeur1 = willekeur;
Math.Round(willekeur1);
for (int i = 1; i <= 12; i++)
{
Console.WriteLine("ik gooide "+willekeur+" ("+Math.Round(willekeur1,2,)+")");
willekeur = r.Next(1, worpen);
}
Console.ReadLine();
I want that ' willekeur1 ' a number which contains a decimal comma is. so example: 12456--> 12,456
You can do: (you need latest c# to use string interpolation)
$"{12456:n0}"; // 12,456
$"{12456:n2}"; // 12,456.00
In your case
Console.WriteLine($"ik gooide {willekeur} ({Math.Round(willekeur1,2,)})");
or
$"{Math.Round(willekeur1,2):n0}";
$"{Math.Round(willekeur1,2):n2}";
this might be useful for you:
public float ReadFloat()
{
float ReadValue = 0;
string KeySequence = "";
string TempKey = "";
bool CommaUsed = false;
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if ((key.Key >= ConsoleKey.D0 && key.Key <= ConsoleKey.D9) || (key.Key >= ConsoleKey.NumPad0 && key.Key <= ConsoleKey.NumPad9))
{
TempKey = Convert.ToString(key.Key);
TempKey = TempKey.Remove(0, 1);
KeySequence += TempKey;
Console.Write(TempKey);
};
if (key.Key == ConsoleKey.OemComma || key.Key == ConsoleKey.Decimal)
{
if (!CommaUsed)
{
KeySequence += ".";
Console.Write(".");
CommaUsed = true;
};
};
if ((key.Key == ConsoleKey.Backspace) && KeySequence != "")
{
string LastChar = KeySequence.Substring(KeySequence.Length - 1);
//MessageBox.Show("Last char: "+LastChar);
//Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator)
char SepDeci = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
if (Convert.ToChar(LastChar) == SepDeci)
{
CommaUsed = false;
};
KeySequence = KeySequence.Remove(KeySequence.Length - 1);
Console.Write("\b \b");
};
}
while (key.Key != ConsoleKey.Enter);
if (KeySequence == "")
{
return 0;
};
ReadValue = Convert.ToSingle(KeySequence);
return ReadValue;
}
this method reads value from console but allows only numbers and one decimal separator (comma or dot, depending on your culture settings).
to use is to read value to a variable:
willekeur1 = ReadFloat();

c# exporting sql data to csv

When exporting my data from sql to excel, it starts with the second line and not the first. I think I've narrowed down the problem to the streamwriter section of code but can't seem to work out where it's going wrong!
This is the code;
public static void ToCsv3(IDataReader myReader, string fileName, bool includeHeaderAsFirstRow)
{
const string Separator = ",";
Stream s = File.Create(fileName + ".txt");
StreamWriter streamWriter = new StreamWriter(s, Encoding.Unicode);
StringBuilder sb = null;
if (includeHeaderAsFirstRow)
{
sb = new StringBuilder();
for (int index = 0; index < myReader.FieldCount; index++)
{
if (myReader.GetName(index) != null)
sb.Append(myReader.GetName(index));
if (index < myReader.FieldCount - 1)
sb.Append(Separator);
}
streamWriter.WriteLine(sb.ToString());
}
int j = 0;
while (myReader.Read())
{
sb = new StringBuilder();
for (int index = 0; index < myReader.FieldCount - 1; index++)
{
if (!myReader.IsDBNull(index))
{
string value = myReader.GetValue(index).ToString();
if (myReader.GetFieldType(index) == typeof(String))
{
if (value.IndexOf("\"") >= 0)
value = value.Replace("\"", "\"\"");
if (value.IndexOf(Separator) >= 0)
value = "\"" + value + "\"";
}
if (j != 0)
{
if (index == 0)
{
sb.Append(Environment.NewLine);
}
}
sb.Append(value);
j = j + 1;
}
if (index < myReader.FieldCount - 1)
sb.Append(Separator);
}
if (!myReader.IsDBNull(myReader.FieldCount - 1))
sb.Append(myReader.GetValue(myReader.FieldCount).ToString().Replace(Separator, " "));
streamWriter.Write(sb.ToString());
}
myReader.Close();
streamWriter.Close();
}
I'd rather decompose the solution into creating CSV and saving it to the file:
public static IEnumerable<String> ToCsv(IDataReader reader,
Boolean includeHeaderAsFirstRow,
Char separator = ',',
Char quotation = '"') {
if (null == reader)
throw new ArgumentNullException("reader");
String qt = quotation.ToString();
StringBuilder Sb = new StringBuilder();
if (includeHeaderAsFirstRow) {
for (int i = 0; i < reader.FieldCount; ++i) {
if (i > 0)
Sb.Append(separator);
String name = reader.GetName(i);
if (name.Contains(separator) || name.Contains(quotation))
name = qt + name.Replace(qt, qt + qt) + qt;
Sb.Append(name);
}
yield return Sb.ToString();
}
while (reader.Read()) {
Sb.Clear();
for (int i = 0; i < reader.FieldCount; ++i) {
if (i > 0)
Sb.Append(separator);
if (!reader.IsDBNull(i)) {
String item = Convert.ToString(reader[i]);
if (item.Contains(separator) || item.Contains(quotation))
item = qt + item.Replace(qt, qt + qt) + qt;
Sb.Append(item);
}
}
yield return Sb.ToString();
}
}
public static void CsvToFile(String fileName,
IDataReader reader,
Char separator = ',',
Char quotation = '"') {
if (String.IsNullOrEmpty(Path.GetExtension(fileName)))
fileName += ".txt"; // ".csv" looks better here
File.WriteAllLines(fileName, ToCsv(reader, separator, quotation));
}

Convert rule condition to rule list

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 ;.

Categories

Resources