Split string with a comma without spliting inside "" with c# only [duplicate] - c#

This question already has answers here:
split a comma-separated string with both quoted and unquoted strings [duplicate]
(16 answers)
Closed 5 years ago.
How to split a string with a comma and don't split inside - "" with c# only.
For example this string "aa","b,b","asdds","sd,fd,sd,,f"
To this array/list - aa,b,b,asdds,sd,fd,sd,,f

string s = "\"aa\",\"b,b\",\"asdds\",\"sd,fd,sd,,f\""; // The string (\" = ") when write it inside string
List<string> s1 = new List<string>(); // List of the strings without the , and the "
string s2 = ""; // string for adding into the list
bool
first = false, // If arrive to the first "
second = false; // If arrive to the second "
foreach (char c in s) // Move over every char in the string
{
if (second) // If reach the second
{
s1.Add(s2); // Add the string to the list
s2 = ""; // Make s2 ready for new string
first = false; // Make first be ready for another string
second = false; // Make second be ready for another string
}
if (first) // If the string in the quotemark started
{
if (c == '"') // If the string in the quotemark ended
{
second = true; // Reach the second quotemark
}
else // If the string didn't end
{
s2 += c; // Add the char to the string
}
}
if (c == '"' && !first && !second) // If the string just reach the first quotemark in a string
{
first = true; // Reach the first quotemark
}
}
if (second&&first) //For the last string that missed at the end
{
s1.Add(s2); // Add the string to the list
}

string sample = "aa","b,b","asdds","sd,fd,sd,,f";
sample = sample.Replace("\",\", "&");
string[] targetA = sample.Split('&');

Related

Can't properly rebuild a string with Replacement values from Dictionary

I am trying to build a file using a template. I am processing the file in a while loop line by line. The first section of the file, first 35 lines are header information. The infromation is surrounded by # signs. Take this string for example:
Field InspectionStationID 3 {"PVA TePla #WSM#", "sw#data.tool_context.TOOL_SOFTWARE_VERSION#", "#data.context.TOOL_ENTITY#"}
The expected output should be:
Field InspectionStationID 3 {"PVA TePla", "sw0.2.002", "WSM102"}
This header section uses a different mapping than the rest of the file so I wanted to parse the file line by line from top to bottom and use a different logic for each section so that I don't waste time parsing the entire file at once multiple times for different sections.
The logic uses two dictionaries populated from an xml file. Because the file has mutliple tables, I combined them in the two dictionaries like so:
var headerCdataIndexKeyVals = Dictionary<string, int>(){
{"data.tool_context.TOOL_SOFTWARE_VERSION", 1},
{"data.context.TOOL_ENTITY",0}
};
var headerCdataArrayKeyVals = new Dictionary<string, List<string>>();
var tool_contextCdataList = new list <string>{"HM654", "sw0.2.002"};
var contextCdataList = new List<string>{"WSM102"}
headerCdataArrayKeyVals.add("tool_context", tool_contextCdataList);
headerCdataArrayKeyVals.add("context", contextCdataList);
To help me map the values to their respective positions in the string in one go and without having to loop through multiple dictionaries.
I am using the following logic:
public static string FindSubsInDelimetersAndReturn(string str, char openDelimiter, char closeDelimiter, HeaderMapperData mapperData )
{
string newString = string.Empty;
// Stores the indices of
Stack <int> dels = new Stack <int>();
for (int i = 0; i < str.Length; i++)
{
var let = str[i];
// If opening delimeter
// is encountered
if (str[i] == openDelimiter && dels.Count == 0)
{
dels.Push(i);
}
// If closing delimeter
// is encountered
else if (str[i] == closeDelimiter && dels.Count > 0)
{
// Extract the position
// of opening delimeter
int pos = dels.Peek();
dels.Pop();
// Length of substring
int len = i - 1 - pos;
// Extract the substring
string headerSubstring = str.Substring(pos + 1, len);
bool hasKey = mapperData.HeaderCdataIndexKeyVals.TryGetValue(headerSubstring.ToUpper(), out int headerCdataIndex);
string[] headerSubstringSplit = headerSubstring.Split('.');
string headerCDataVal = string.Empty;
if (hasKey)
{
if (headerSubstring.Contains("CONTAINER.CONTEXT", StringComparison.OrdinalIgnoreCase))
{
headerCDataVal = mapperData.HeaderCdataArrayKeyVals[headerSubstringSplit[1].ToUpper() + '.' + headerSubstringSplit[2].ToUpper()][headerCdataIndex];
//mapperData.HeaderCdataArrayKeyVals[]
}
else
{
headerCDataVal = mapperData.HeaderCdataArrayKeyVals[headerSubstringSplit[1].ToUpper()][headerCdataIndex];
}
string strToReplace = openDelimiter + headerSubstring + closeDelimiter;
string sub = str.Remove(i + 1);
sub = sub.Replace(strToReplace, headerCDataVal);
newString += sub;
}
else if (headerSubstring == "WSM" && closeDelimiter == '#')
{
string sub = str.Remove(len + 1);
newString += sub.Replace(openDelimiter + headerSubstring + closeDelimiter, "");
}
else
{
newString += let;
}
}
}
return newString;
}
}
But my output turns out to be:
"\tFie\tField InspectionStationID 3 {\"PVA TePla#WSM#\", \"sw0.2.002\tField InspectionStationID 3 {\"PVA TePla#WSM#\", \"sw#data.tool_context.TOOL_SOFTWARE_VERSION#\", \"WSM102"
Can someone help understand why this is happening and how I can go about correcting it so I get the output:
Field InspectionStationID 3 {"PVA TePla", "sw0.2.002", "WSM102"}
Am i even trying to solve this the right way or is there a better cleaner way to do it? Btw if the key is not in the dictionary I replace it with empty string

How to add padding to the left and right of a whole paragraph in C# Console?

I'm having an issue figuring out how to add padding to the whole of a body of text. My code is below.
public static String Format(List<string> list, int leftMargin, int rightMargin)
{
// Create an empty string to put the list of words into
string listTurnedIntoAString = "";
// Define the type of punctuation that is acceptable for have a space after.
string punctuation = ".,?!";
// turn the list of strings into one string
foreach (string item in list)
{
// if we find a punctuation mark remove the space before it
if (item.IndexOfAny(punctuation.ToCharArray()) == 0 && listTurnedIntoAString != String.Empty)
{
// Remove the space before the punctuation mark
listTurnedIntoAString = listTurnedIntoAString.Remove(listTurnedIntoAString.Length - 1);
}
// Add the next word to the string.
listTurnedIntoAString += $"{item} ";
}
// Add padding the left side
var stringPaddedLeft = listTurnedIntoAString.PadLeft(leftMargin + listTurnedIntoAString.Length);
// Add padding to the right side
var stringPaddedBothSides = stringPaddedLeft.PadRight(rightMargin + stringPaddedLeft.Length);
// Return the formated string
return stringPaddedBothSides;
}
What I'm Getting:
Output needed(!):
you have to change the Console.Write part of your program
as is beautifully explained in this issue: Display formatted text on console using padding
you have to declare a max line width, and for each line you write on console, you should write a empty string with length of leftMargin
Each line has to be parsed individually.
public static String Format(List<string> list, int leftMargin, int rightMargin)
{
// Create an empty string to put the list of words into
string listTurnedIntoAString = "";
// Define the type of punctuation that is acceptable for have a space after.
string punctuation = ".,?!-;";
// turn the list of strings into one string
foreach (string item in list)
{
// if we find a punctuation mark remove the space before it
if (item.IndexOfAny(punctuation.ToCharArray()) == 0 && listTurnedIntoAString != String.Empty)
{
// Remove the space before the punctuation mark
listTurnedIntoAString = listTurnedIntoAString.Remove(listTurnedIntoAString.Length - 1);
}
// Add the next word to the string.
listTurnedIntoAString += $"{item} ";
}
// Number of charters between each margin
int betweenMarginSpacing = rightMargin - leftMargin;
// Placeholder for the a new formatted string
string formattedString = "";
while (listTurnedIntoAString != String.Empty)
{
// check if we are close to the end of the list
if (listTurnedIntoAString.Length > betweenMarginSpacing)
{
// format each line
formattedString += $"{listTurnedIntoAString.Substring(0, betweenMarginSpacing).PadLeft(leftMargin + betweenMarginSpacing)}\n";
// remove the text from the unformatted string after it has been added to the formatted string.
listTurnedIntoAString = listTurnedIntoAString.Substring(betweenMarginSpacing);
}
else // we are at the end of the string
{
// append the rest of the string to the formatted string.
formattedString += listTurnedIntoAString.PadLeft(leftMargin + listTurnedIntoAString.Length);
// declare the formatted string empty
listTurnedIntoAString = String.Empty;
}
}
// Return the formated string
return formattedString;
}

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

split string and store it in another variable in c# [duplicate]

This question already has answers here:
Split string using backslash
(3 answers)
Closed 5 years ago.
How to Read character after '\':
string PrName = "software\Plan Mobile";
First of all, do not forget #:
string PrName = #"software\Plan Mobile";
Next, if you want just the tail only (i.e. "Plan Mobile") then Substring will do:
// if no '\' found, the entire string will be return
string tail = PrName.Substring(PrName.IndexOf('\\') + 1);
If you want both (all parts), try Split:
// parts[0] == "software"
// parts[1] == "Plan Mobile"
string[] parts = PrName.Split('\\');
Try this:
char charToFind = '\';
string PrName = "software\Plan Mobile";
int indexOfChar = PrName.IndexOf(charToFind);
if (indexOfChar >= 0)
{
string result = PrName.Substring(indexOfChar + 1);
}
Output: result = "Plan Mobile"
I think, you want to split string
string s = "software\Plan Mobile";
// Split string on '\'.
string[] words = s.Split('\');
foreach (string word in words)
{
Console.WriteLine(word);
}
Output:
software
Plan mobile

C# string parse

I have string like this
string temp = "'ADDR_LINE_2','MODEL','TABLE',5,'S','Y','C40','MUL,NBLD,NITA,NUND','','Address line 2'"
Each pair of single quote is a field delimited by a comma. I want to empty the 8th field in the string. I cannot simply do replace("MUL,NBLD,NITA,NUND","") because that field could contain anything. also please note the the 4th field is a number and therefore has no single quote around 5.
How can I achieve this?
static void Main()
{
var temp = "'ADDR_LINE_2','MODEL','TABLE',5,'S','Y','C40','MUL,NBLD,NITA,NUND','','Address line 2'";
var parts = Split(temp).ToArray();
parts[7] = null;
var ret = string.Join(",", parts);
// or replace the above 3 lines with this...
//var ret = string.Join(",", Split(temp).Select((v,i)=>i!=7 ? v : null));
//ret == "'ADDR_LINE_2','MODEL','TABLE',5,'S','Y','C40',,'','Address line 2'"
}
public static IEnumerable<string> Split(string input, char delimiter = ',', char quote = '\'')
{
string temp = "";
bool skipDelimiter = false;
foreach (var c in input)
{
if (c == quote)
skipDelimiter = !skipDelimiter;
else if (c == delimiter && !skipDelimiter)
{
//do split
yield return temp;
temp = "";
continue;
}
temp += c;
}
yield return temp;
}
I made a small implementation below. I explain the logic in the comments. Basically you want to write a simple parser to accomplish what you described.
edit0: just realized I did the opposite of what you asked for oops..fixed now
edit1: replacing the string with null as opposed to eliminating the entire field from the comma-delimited list.
static void Main(string[] args)
{
string temp = "'ADDR_LINE_2','MODEL','TABLE',5,'S','Y','C40','MUL,NBLD,NITA,NUND','','Address line 2'";
//keep track of the single quotes
int singleQuoteCount= 0;
//keep track of commas
int comma_count = 0;
String field = "";
foreach (Char chr in temp)
{
//add to the field string if we are not between the 7th and 8th comma not counting commas between single quotes
if (comma_count != 7)
field += chr;
//plug in null string between two single quotes instead of whatever chars are in the eigth field.
else if (chr == '\'' && singleQuoteCount %2 ==1)
field += "\'',";
if (chr == '\'') singleQuoteCount++;
//only want to add to comma_count if we are outside of single quotes.
if (singleQuoteCount % 2 == 0 && chr == ',') comma_count++;
}
}
If you would use '-' (or other char) instead of ',' inside of the fields (exam: 'MUL-NBLD-NITA-NUND'), you could use this code:
static void Main(string[] args)
{
string temp = "'ADDR_LINE_2','MODEL','TABLE',5,'S','Y','C40','MUL-NBLD-NITA-NUND','','Address line 2'";
temp = replaceField(temp, 8);
}
static string replaceField(string list, int field)
{
string[] fields = list.Split(',');
string chosenField = fields[field - 1 /*<--Arrays start at 0!*/];
if(!(field == fields.Length))
list = list.Replace(chosenField + ",", "");
else
list = list.Replace("," + chosenField, "");
return list;
}
//Return-Value: "'ADDR_LINE_2','MODEL','TABLE',5,'S','Y','C40','','Address line 2'"

Categories