How to find character after pipe "|" in C# - c#

I would like to find character after | and check in a loop in C#.
Like I have Test|T1. After pipe the character could be anything like Test|T2 or Test|T3.
The first value is Table|Y and second value could be Test|T1, Test|T2 or Test|T3.
So I would like to check the character after | in else block.
foreach (var testing in TestQuestion.Split(','))
{
if(testing.Equals("Table|Y"))
{
order.OrderProperties.Add(new OrderProperty("A")
{
...
});
}
else
{
//check the value after "|"
}
}
So I would like to check the character after | in else block.

like this
var s = "XXX|T1234";
var idx = s.IndexOf("|");
if (idx > -1) // found
{
var nextChar = s.Substring(idx + 1, 1);
}
if its possible that '|' is the last character then you need to check for that

Another way to do this,
var tokens = test.Split('|');
if (tokens.FirstOrDefault() == "Test" && tokens.LastOrDefault() == "T1")
{
}

You can do it this way (to test if value is T1 for example):
if (testing.Split('|')[0] == "Test" && testing.Split('|')[1] == "T1")
{
}

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

text parsing application c# without third party libraries

For example, there is a line:
name, tax, company.
To separate them i need a split method.
string[] text = File.ReadAllLines("file.csv", Encoding.Default);
foreach (string line in text)
{
string[] words = line.Split(',');
foreach (string word in words)
{
Console.WriteLine(word);
}
}
Console.ReadKey();
But how to divide if in quotes the text with a comma is indicated:
name, tax, "company, Ariel";<br>
"name, surname", tax, company;<br> and so on.
To make it like this :
Max | 12.3 | company, Ariel
Alex, Smith| 13.1 | Oriflame
It is necessary to take into account that the input data will not always be in an ideal format (as in the example). That is, there may be 3 quotes in a row or a string without commas. The program should not fall in any case. If it is impossible to parse, then issue a message about it.
Split using double quotes first. And Split using comma on the first string.
You can use TextFieldParser from Microsoft.VisualBasic.FileIO
var list = new List<Data>();
var isHeader=true;
using (TextFieldParser parser = new TextFieldParser(filePath))
{
parser.Delimiters = new string[] { "," };
while (true)
{
string[] parts = parser.ReadFields();
if(isHeader)
{
isHeader = false;
continue;
}
if (parts == null)
break;
list.Add(new Data
{
People = parts[0],
Tax = Double.Parse(parts[1]),
Company = parts[2]
});
}
}
Where Data is defined as
public class Data
{
public string People{get;set;}
public double Tax{get;set;}
public string Company{get;set;}
}
Please note you need to include Microsoft.VisualBasic.FileIO
Example Data,
Name,Tax,Company
Max,12.3,"company, Ariel"
Ariel,13.1,"company, Oriflame"
Output
Here's a bit of code that might help, not the most efficient but I use it to 'see' what is going on with the parsing if a particular line is giving trouble.
string[] text = File.ReadAllLines("file.csv", Encoding.Default);
string[] datArr;
string tmpStr;
foreach (string line in text)
{
ParseString(line, ",", "!####!", out datArr, out tmpStr)
foreach(string s in datArr)
{
Console.WriteLine(s);
}
}
Console.ReadKey();
private static void ParseString(string inputString, string origDelim, string newDelim, out string[] retArr, out string retStr)
{
string tmpStr = inputString;
retArr = new[] {""};
retStr = "";
if (!string.IsNullOrWhiteSpace(tmpStr))
{
//If there is only one Quote character in the line, ignore/remove it:
if (tmpStr.Count(f => f == '"') == 1)
tmpStr = tmpStr.Replace("\"", "");
string[] tmpArr = tmpStr.Split(new[] {origDelim}, StringSplitOptions.None);
var inQuote = 0;
StringBuilder lineToWrite = new StringBuilder();
foreach (var s in tmpArr)
{
if (s.Contains("\""))
inQuote++;
switch (inQuote)
{
case 1:
//Begin quoted text
lineToWrite.Append(lineToWrite.Length > 0
? newDelim + s.Replace("\"", "")
: s.Replace("\"", ""));
if (s.Length > 4 && s.Substring(0, 2) == "\"\"" && s.Substring(s.Length - 2, 2) != "\"\"")
{
//if string has two quotes at the beginning and is > 4 characters and the last two characters are NOT quotes,
//inquote needs to be incremented.
inQuote++;
}
else if ((s.Substring(0, 1) == "\"" && s.Substring(s.Length - 1, 1) == "\"" &&
s.Length > 1) || (s.Count(x => x == '\"') % 2 == 0))
{
//if string has more than one character and both begins and ends with a quote, then it's ok and counter should be reset.
//if string has an EVEN number of quotes, it should be ok and counter should be reset.
inQuote = 0;
}
else
{
inQuote++;
}
break;
case 2:
//text between the quotes
//If we are here the origDelim value was found between the quotes
//include origDelim so there is no data loss.
//Example quoted text: "Dr. Mario, Sr, MD";
// ", Sr" would be handled here
// ", MD" would be handled in case 3 end of quoted text.
lineToWrite.Append(origDelim + s);
break;
case 3:
//End quoted text
//If we are here the origDelim value was found between the quotes
//and we are at the end of the quoted text
//include origDelim so there is no data loss.
//Example quoted text: "Dr. Mario, MD"
// ", MD" would be handled here.
lineToWrite.Append(origDelim + s.Replace("\"", ""));
inQuote = 0;
break;
default:
lineToWrite.Append(lineToWrite.Length > 0 ? newDelim + s : s);
break;
}
}
if (lineToWrite.Length > 0)
{
retStr = lineToWrite.ToString();
retArr = tmpLn.Split(new[] {newDelim}, StringSplitOptions.None);
}
}
}

C# string.split() separate string by uppercase

I've been using the Split() method to split strings. But this work if you set some character for condition in string.Split(). Is there any way to split a string when is see Uppercase?
Is it possible to get few words from some not separated string like:
DeleteSensorFromTemplate
And the result string is to be like:
Delete Sensor From Template
Use Regex.split
string[] split = Regex.Split(str, #"(?<!^)(?=[A-Z])");
Another way with regex:
public static string SplitCamelCase(string input)
{
return System.Text.RegularExpressions.Regex.Replace(input, "([A-Z])", " $1", System.Text.RegularExpressions.RegexOptions.Compiled).Trim();
}
If you do not like RegEx and you really just want to insert the missing spaces, this will do the job too:
public static string InsertSpaceBeforeUpperCase(this string str)
{
var sb = new StringBuilder();
char previousChar = char.MinValue; // Unicode '\0'
foreach (char c in str)
{
if (char.IsUpper(c))
{
// If not the first character and previous character is not a space, insert a space before uppercase
if (sb.Length != 0 && previousChar != ' ')
{
sb.Append(' ');
}
}
sb.Append(c);
previousChar = c;
}
return sb.ToString();
}
I had some fun with this one and came up with a function that splits by case, as well as groups together caps (it assumes title case for whatever follows) and digits.
Examples:
Input -> "TodayIUpdated32UPCCodes"
Output -> "Today I Updated 32 UPC Codes"
Code (please excuse the funky symbols I use)...
public string[] SplitByCase(this string s) {
var ʀ = new List<string>();
var ᴛ = new StringBuilder();
var previous = SplitByCaseModes.None;
foreach(var ɪ in s) {
SplitByCaseModes mode_ɪ;
if(string.IsNullOrWhiteSpace(ɪ.ToString())) {
mode_ɪ = SplitByCaseModes.WhiteSpace;
} else if("0123456789".Contains(ɪ)) {
mode_ɪ = SplitByCaseModes.Digit;
} else if(ɪ == ɪ.ToString().ToUpper()[0]) {
mode_ɪ = SplitByCaseModes.UpperCase;
} else {
mode_ɪ = SplitByCaseModes.LowerCase;
}
if((previous == SplitByCaseModes.None) || (previous == mode_ɪ)) {
ᴛ.Append(ɪ);
} else if((previous == SplitByCaseModes.UpperCase) && (mode_ɪ == SplitByCaseModes.LowerCase)) {
if(ᴛ.Length > 1) {
ʀ.Add(ᴛ.ToString().Substring(0, ᴛ.Length - 1));
ᴛ.Remove(0, ᴛ.Length - 1);
}
ᴛ.Append(ɪ);
} else {
ʀ.Add(ᴛ.ToString());
ᴛ.Clear();
ᴛ.Append(ɪ);
}
previous = mode_ɪ;
}
if(ᴛ.Length != 0) ʀ.Add(ᴛ.ToString());
return ʀ.ToArray();
}
private enum SplitByCaseModes { None, WhiteSpace, Digit, UpperCase, LowerCase }
Here's another different way if you don't want to be using string builders or RegEx, which are totally acceptable answers. I just want to offer a different solution:
string Split(string input)
{
string result = "";
for (int i = 0; i < input.Length; i++)
{
if (char.IsUpper(input[i]))
{
result += ' ';
}
result += input[i];
}
return result.Trim();
}

RegEx.Replace is only replacing first occurrence, need all

I'm having an issue with Regex.Replace in C# as it doesn't seem to be replacing all occurrences of the matched pattern.
private string ReplaceBBCode(string inStr)
{
var outStr = Regex.Replace(inStr, #"\[(b|i|u)\](.*?)\[/\1\]", #"<$1>$2</$1>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
outStr = Regex.Replace(outStr, "(\r|\n)+", "<br />");
return outStr;
}
The input string:
[b]Saint Paul's Food Kitchen[/b] [b] [/b]Saint Paul's food kitchen opens weekly to provide food to those in need.
The result:
<b>Saint Paul's Food Kitchen</b> [b] [/b]Saint Paul's food kitchen opens weekly to provide food to those in need.
I've tested this in regexhero.net and it works exactly as it should there.
EDIT:
Sorry, copied the wrong version of the function. It now shows the correct code, that behaves incorrectly for me.
The output I'm getting is completely different from what you say you're getting, but
The biggest problem I see, is that you probably don't want your regex to be greedy.
try replacing the .* with .*?
No need for Regex:
private static string ReplaceBBCode(string inStr)
{
return inStr.Replace("[b]", "<b>").Replace("[/b]", "</b>")
.Replace("[i]", "<i>").Replace("[/i]", "</i>")
.Replace("[u]", "<u>").Replace("[/u]", "</u>")
.Replace("\r\n", "\n")
.Replace("\n", "<br />");
}
I like this one better:
private static string ReplaceBBCode(string inStr)
{
StringBuilder outStr = new StringBuilder();
bool addBR = false;
for(int i=0; i<inStr.Length; i++){
if (addBR){
outStr.Append("<br />");
addBR = false;
}
if (inStr[i] == '\r' || inStr[i] == '\n'){
if (!addBR)
addBR = true;
}
else {
addBR = false;
if (i+2 < inStr.Length && inStr[i] == '['
&& (inStr[i+1] == 'b' || inStr[i+1] == 'i' || inStr[i+1] == 'u')
&& inStr[i+2] == ']'){
outStr.Append("<").Append(inStr[i+1]).Append(">");
i+=2;
}
else if(i+3 < inStr.Length && inStr[i] == '[' && inStr[i+1] == '/'
&& (inStr[i+2] == 'b' || inStr[i+2] == 'i' || inStr[i+2] == 'u')
&& inStr[i+3] == ']'){
outStr.Append("</").Append(inStr[i+2]).Append(">");
i+=3;
}
else
outStr.Append(inStr[i]);
}
}
return outStr.ToString();
}
This solved the issue, it also handles nested tags. Not sure why, but rebuilding over and over it still was causing errors. Its possible our VS2010 is corrupted and not building properly, or that the framework is corrupted. Not sure what the cause of the problem is, but this solved it:
private string ReplaceBBCode(string inStr)
{
var outStr = inStr;
var bbre = new Regex(#"\[(b|i|u)\](.*?)\[/\1\]", RegexOptions.IgnoreCase | RegexOptions.Multiline);
while( bbre.IsMatch(outStr))
outStr = bbre.Replace(outStr, #"<$1>$2</$1>");
outStr = Regex.Replace(outStr, "(\r|\n)+", "<br />");
return outStr;
}

How to replace only one part of a sub string from a string containing more than one similar parts?

I might have not stated the question as what I would like to. Please consider below scenario.
Scenario:
I am implementing a Search/Replace functionality in my C# Win Form application. This feature will have the option to replace a substring that "starts with" or "ends with" a certain value. For example:
A string contains "123ABCD". Replacing "123" with "XYZ" should produce: "XYZABCD"
A string contains "ABCD123". Replacing "123" with "XYZ" should produce: "ABCDXYZ"
Both of these features are working fine. My problem is when the string contains "123ABCD123". Both operations return the wrong value when using "XYZ".
"starts with" produces "XYZABCDXYZ", instead of "XYZABCD"
"ends with" produces "XYZABCDXYZ" instead of "ABCDXYZ"
Can anyone give me an idea how to achieve that?
Thanks !!!
Code Snippet:
if (this.rbMatchFieldsStartedWith.Checked)
{
if (caseSencetive)
{
matched = currentCellValue.StartsWith(findWhat);
}
else
{
matched = currentCellValue.ToLower().StartsWith(findWhat.ToLower());
}
}
else if (this.rbMatchFieldsEndsWith.Checked)
{
if (caseSencetive)
{
matched = currentCellValue.EndsWith(findWhat);
}
else
{
matched = currentCellValue.ToLower().EndsWith(findWhat.ToLower());
}
}
if (matched)
{
if (replace)
{
if (this.rbMatchWholeField.Checked)
{
currentCell.Value = replaceWith;
}
else
{
currentCellValue = currentCellValue.Replace(findWhat, replaceWith);
currentCell.Value = currentCellValue;
}
this.QCGridView.RefreshEdit();
}
else
{
currentCell.Style.BackColor = Color.Aqua;
}
}
Implement the replacement method dependent on the search mode.
Replace the line
currentCellValue = currentCellValue.Replace(findWhat, replaceWith);
with
if (this.rbMatchFieldsStartedWith.Checked)
{
// target string starts with findWhat, so remove findWhat and prepend replaceWith
currentCellValue = replaceWith + currentCellValue.SubString(findWhat.Length);
}
else
{
// target string end with findWhat, so remove findWhat and append replaceWith.
currentCellValue = currentCellValue.SubString(0, currentCellValue.Length - findWhat.Length) + replaceWith;
}
currentCell.Value = newValue;
This sounds like a good one for regular expressions.
It is supported by .NET, and also has a replacement syntax.
I just want to try a replacement method without using regex.
(Regex could be the right way to do it, but it was funny to find an alternative)
void Main()
{
string test = "123ABCD123"; // String to change
string rep = "XYZ"; // String to replace
string find = "123"; // Replacement string
bool searchStart = true; // Flag for checkbox startswith
bool searchEnd = true; // Flag for checkbox endswith
bool caseInsensitive = true; // Flag for case type replacement
string result = test;
int pos = -1;
int lastPos = -1;
if(caseInsensitive == true)
{
pos = test.IndexOf(find, StringComparison.InvariantCultureIgnoreCase);
lastPos = test.LastIndexOf(find, StringComparison.InvariantCultureIgnoreCase);
}
else
{
pos = test.IndexOf(find, StringComparison.Ordinal);
lastPos = test.LastIndexOf(find, StringComparison.Ordinal);
}
result = test;
if(pos == 0 && searchStart == true)
{
result = rep + test.Substring(find.Length);
}
if(lastPos != 0 && lastPos != pos && lastPos + find.Length == test.Length && searchEnd == true)
{
result = result.Substring(0, lastPos) + rep;
}
Console.WriteLine(result);
}
First off all let's trace your scenario assuming:
string to work on is 123ABCD123
starts with is checked.
aim is to replace "123" with "XYZ"
by just reading your code. We hit if (this.rbMatchFieldsStartedWith.Checked) and which evaluates to true. So we step in that block. We hit matched = currentCellValue.StartsWith(findWhat); and matched = true. We continue with if (matched) condition which also evaluates to true. After that if (replace) evaluates to true. Finally we make the last decision with if (this.rbMatchWholeField.Checked) which evaluates to false so we continue with else block:
currentCellValue = currentCellValue.Replace(findWhat, replaceWith);
currentCell.Value = currentCellValue;
First line in this block replaces all the occurrences of findWhat with replaceWith, namely all the occurrences of 123 with XYZ. Of course this is not the desired behaviour. Instead of Replace you must use a function that replaces just the first or the last occurrence of the string according to the input of course.

Categories