I have to implement a very big If and else statement in a short and smarter way.
for example :
If(seg.status =="hl"||seg.status =="hl2"||seg.status =="hl3"||seg.status =="hl4"||seg.status =="hl4"||seg.status =="hl5"||seg.status =="hl6"||seg.status =="hl7")
into small and smarter way
How about adding all your hl strings in a List<string> and check with Any and Contains like;
var list = new List<string>(){"hl", "hl1", "hl2", ...};
if(!list.Any(seg.status.Contains))
As Jon warned, this will return true if your string doesn't match with status, choose
if(list.Contains(seg.status))
instead.
I would put them into a HashSet:
var keywords = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase)
{
"h1", "hl2", ...
}
And then check if it contains the given word:
if(keywords.Contains(seg.status))
{
// ToDo: What shall happen?
}
You could also use regex:
Regex.IsMatch(seg.status, #"hl\d*")
You can try like this
var segList = new List<string>(){"hl", "hl1", "hl2","hl4", "hl15", "hl6","hl7"};
If(segList.contains(seg.status))
Do you do this in many places? If so, you could write a little string extension class to make the code more tidy:
public static class StringExt
{
public static bool MatchesAnyOf(this string text, params string[] targets)
{
return targets.Any(target => string.Compare(text, target, StringComparison.OrdinalIgnoreCase) == 0);
}
}
And you would call it like this:
if (seg.status.MatchesAnyOf("hl", "hl1", "hl2","hl4", "hl15", "hl6","hl7"))
(If you want a case-sensitive comparison, remove the StringComparison.OrdinalIgnoreCase parameter from string.Compare().)
If you are confident on the pattern of the test variables naming:
using System.Text.RegularExpressions;
Regex re = new Regex("hl[1|2|3|4|5|6|7]");
string[] test= {"hl1","hl2","hl3","hl4","hl5","hl6","hl7","hlasdfasdf"};
for(int i = 0; i < test.Length; i++){
System.Console.WriteLine(test[i] + ":" + (re.IsMatch(test[i])?"match":"does not match"));
}
So in your case:
if(re.IsMatch(seg.status)){ //... }
Related
I got bunch of strings in text, which looks like something like this:
h1. this is the Header
h3. this one the header too
h111. and this
And I got function, which suppose to process this text depends on what lets say iteration it been called
public void ProcessHeadersInText(string inputText, int atLevel = 1)
so the output should look like one below in case of been called
ProcessHeadersInText(inputText, 2)
Output should be:
<h3>this is the Header<h3>
<h5>this one the header too<h5>
<h9 and this <h9>
(last one looks like this because of if value after h letter is more than 9 it suppose to be 9 in the output)
So, I started to think about using regex.
Here's the example https://regex101.com/r/spb3Af/1/
(As you can see I came up with regex like this (^(h([\d]+)\.+?)(.+?)$) and tried to use substitution on it <h$3>$4</h$3>)
Its almost what I'm looking for but I need to add some logic into work with heading level.
Is it possible to add any work with variables in substitution?
Or I need to find other way? (extract all heading first, replace em considering function variables and value of the header, and only after use regex I wrote?)
The regex you may use is
^h(\d+)\.+\s*(.+)
If you need to make sure the match does not span across line, you may replace \s with [^\S\r\n]. See the regex demo.
When replacing inside C#, parse Group 1 value to int and increment the value inside a match evaluator inside Regex.Replace method.
Here is the example code that will help you:
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.IO;
public class Test
{
// Demo: https://regex101.com/r/M9iGUO/2
public static readonly Regex reg = new Regex(#"^h(\d+)\.+\s*(.+)", RegexOptions.Compiled | RegexOptions.Multiline);
public static void Main()
{
var inputText = "h1. Topic 1\r\nblah blah blah, because of bla bla bla\r\nh2. PartA\r\nblah blah blah\r\nh3. Part a\r\nblah blah blah\r\nh2. Part B\r\nblah blah blah\r\nh1. Topic 2\r\nand its cuz blah blah\r\nFIN";
var res = ProcessHeadersInText(inputText, 2);
Console.WriteLine(res);
}
public static string ProcessHeadersInText(string inputText, int atLevel = 1)
{
return reg.Replace(inputText, m =>
string.Format("<h{0}>{1}</h{0}>", (int.Parse(m.Groups[1].Value) > 9 ?
9 : int.Parse(m.Groups[1].Value) + atLevel), m.Groups[2].Value.Trim()));
}
}
See the C# online demo
Note I am using .Trim() on m.Groups[2].Value as . matches \r. You may use TrimEnd('\r') to get rid of this char.
You can use a Regex like the one used below to fix your issues.
Regex.Replace(s, #"^(h\d+)\.(.*)$", #"<$1>$2<$1>", RegexOptions.Multiline)
Let me explain you what I am doing
// This will capture the header number which is followed
// by a '.' but ignore the . in the capture
(h\d+)\.
// This will capture the remaining of the string till the end
// of the line (see the multi-line regex option being used)
(.*)$
The parenthesis will capture it into variables that can be used as "$1" for the first capture and "$2" for the second capture
Try this:
private static string ProcessHeadersInText(string inputText, int atLevel = 1)
{
// Group 1 = value after 'h'
// Group 2 = Content of header without leading whitespace
string pattern = #"^h(\d+)\.\s*(.*?)\r?$";
return Regex.Replace(inputText, pattern, match => EvaluateHeaderMatch(match, atLevel), RegexOptions.Multiline);
}
private static string EvaluateHeaderMatch(Match m, int atLevel)
{
int hVal = int.Parse(m.Groups[1].Value) + atLevel;
if (hVal > 9) { hVal = 9; }
return $"<h{hVal}>{m.Groups[2].Value}</h{hVal}>";
}
Then just call
ProcessHeadersInText(input, 2);
This uses the Regex.Replace(string, string, MatchEvaluator, RegexOptions) overload with a custom evaluator function.
You could of course streamline this solution into a single function with an inline lambda expression:
public static string ProcessHeadersInText(string inputText, int atLevel = 1)
{
string pattern = #"^h(\d+)\.\s*(.*?)\r?$";
return Regex.Replace(inputText, pattern,
match =>
{
int hVal = int.Parse(match.Groups[1].Value) + atLevel;
if (hVal > 9) { hVal = 9; }
return $"<h{hVal}>{match.Groups[2].Value}</h{hVal}>";
},
RegexOptions.Multiline);
}
A lot of good solution in this thread, but I don't think you really need a Regex solution for your problem. For fun and challenge, here a non regex solution:
Try it online!
using System;
using System.Linq;
public class Program
{
public static void Main()
{
string extractTitle(string x) => x.Substring(x.IndexOf(". ") + 2);
string extractNumber(string x) => x.Remove(x.IndexOf(". ")).Substring(1);
string build(string n, string t) => $"<h{n}>{t}</h{n}>";
var inputs = new [] {
"h1. this is the Header",
"h3. this one the header too",
"h111. and this" };
foreach (var line in inputs.Select(x => build(extractNumber(x), extractTitle(x))))
{
Console.WriteLine(line);
}
}
}
I use C#7 nested function and C#6 interpolated string. If you want, I can use more legacy C#. The code should be easy to read, I can add comments if needed.
C#5 version
using System;
using System.Linq;
public class Program
{
static string extractTitle(string x)
{
return x.Substring(x.IndexOf(". ") + 2);
}
static string extractNumber(string x)
{
return x.Remove(x.IndexOf(". ")).Substring(1);
}
static string build(string n, string t)
{
return string.Format("<h{0}>{1}</h{0}>", n, t);
}
public static void Main()
{
var inputs = new []{
"h1. this is the Header",
"h3. this one the header too",
"h111. and this"
};
foreach (var line in inputs.Select(x => build(extractNumber(x), extractTitle(x))))
{
Console.WriteLine(line);
}
}
}
I have a string that looks like this
2,"E2002084700801601390870F"
3,"E2002084700801601390870F"
1,"E2002084700801601390870F"
4,"E2002084700801601390870F"
3,"E2002084700801601390870F"
This is one whole string, you can imagine it being on one row.
And I want to split this in the way they stand right now like this
2,"E2002084700801601390870F"
I cannot change the way it is formatted. So my best bet is to split at every second quotation mark. But I haven't found any good ways to do this. I've tried this https://stackoverflow.com/a/17892392/2914876 But I only get an error about invalid arguements.
Another issue is that this project is running .NET 2.0 so most LINQ functions aren't available.
Thank you.
Try this
var regEx = new Regex(#"\d+\,"".*?""");
var lines = regex.Matches(txt).OfType<Match>().Select(m => m.Value).ToArray();
Use foreach instead of LINQ Select on .Net 2
Regex regEx = new Regex(#"\d+\,"".*?""");
foreach(Match m in regex.Matches(txt))
{
var curLine = m.Value;
}
I see three possibilities, none of them are particularly exciting.
As #dvnrrs suggests, if there's no comma where you have line-breaks, you should be in great shape. Replace ," with something novel. Replace the remaining "s with what you need. Replace the "something novel" with ," to restore them. This is probably the most solid--it solves the problem without much room for bugs.
Iterate through the string looking for the index of the next " from the previous index, and maintain a state machine to decide whether to manipulate it or not.
Split the string on "s and rejoin them in whatever way works the best for your application.
I realize regular expressions will handle this but here's a pure 2.0 way to handle as well. It's much more readable and maintainable in my humble opinion.
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
const string data = #"2,""E2002084700801601390870F""3,""E2002084700801601390870F""1,""E2002084700801601390870F""4,""E2002084700801601390870F""3,""E2002084700801601390870F""";
var parsedData = ParseData(data);
foreach (var parsedDatum in parsedData)
{
Console.WriteLine(parsedDatum);
}
Console.ReadLine();
}
private static IEnumerable<string> ParseData(string data)
{
var results = new List<string>();
var split = data.Split(new [] {'"'}, StringSplitOptions.RemoveEmptyEntries);
if (split.Length % 2 != 0)
{
throw new Exception("Data Formatting Error");
}
for (var index = 0; index < split.Length / 2; index += 2)
{
results.Add(string.Format(#"""{0}""{1}""", split[index], split[index + 1]));
}
return results;
}
}
}
Wonder if someone could point me in the right direction. What I'd like to achieve is to split a string based upon it having a '/' in it. For example if I had: www.site.com/course/123456/216 in code (c#) I'd like to be able to split the string in code so that 123456 could be assigned to variable param1 and 216 be assigned to param2 (course is the 'friendly' name of the page). If I was to add a third '/' on the string I'd like this to become param3, etc, etc.
Ideally I'd like to be able to put this code somewhere that I could include it on whichever usercontrols I'd need it to work.
Uri.Segments maybe what you are looking for:
new Uri("http://www.contoso.com/foo/bar/index.htm#search").Segments
Results in [ "/", "foo/", "bar/", "index.html" ]
Why not just use split?
var valueArray = "www.site.com/course/123456/216".Split('/');
The array will have the entire string broken up
index 0 would be "www.site.com" and so forth.
HttpContext.Current.Request.Url.AbsolutePath.Split('/')
Well, making the assumption that the values would not have / in them:
var splitVals = queryString.Split('/');
var vals = new Dictionary<string, string>();
for (int i = 2; i <= splitVals.Count; i++)
{
vals.Add(string.Format("param{0}", i), vals[i]);
}
That would get you started. Now, if you're looking to set them to real variables then you'd need to do some casting and leverage reflection, but your question isn't near clear enough to make any real assumptions there.
EDIT
To make this code reusable I would build an extension method:
namespace System
{
public static class StringExtensions
{
public static Dictionary<string, string> SplitQueryString(this string queryString)
{
var splitVals = queryString.Split('/');
var vals = new Dictionary<string, string>();
for (int i = 2; i <= splitVals.Count; i++)
{
vals.Add(string.Format("param{0}", i), vals[i]);
}
return vals;
}
}
}
because then you could do this:
var vals = queryString.SplitQueryString();
http://msdn.microsoft.com/en-us/library/b873y76a.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
string QueryString = "1234/567/890";
string[] QueryArray = QueryString.Split('/');
Now QueryArray[0] = 1234, QueryArray[1] = 567, QueryArray[2] = 890,
url: server/func2/SubFunc2
// Get path components. Trailing separators. Returns { "/", "func2/", "sunFunc2" }.
string[] pathsegments = myUri.Segments;
I have a list of a Sharepoint items: each item has a title, a description and a type.
I successfully retrieved it, I called it result. I want to first check if there is any item in result which starts with A then B then C, etc. I will have to do the same for each alphabet character and then if I find a word starting with this character I will have to display the character in bold.
I initially display the characters using this function:
private string generateHeaderScripts(char currentChar)
{
string headerScriptHtml = "$(document).ready(function() {" +
"$(\"#myTable" + currentChar.ToString() + "\") " +
".tablesorter({widthFixed: true, widgets: ['zebra']})" +
".tablesorterPager({container: $(\"#pager" + currentChar.ToString() +"\")}); " +
"});";
return headerScriptHtml;
}
How can I check if a word starts with a given character?
To check one value, use:
string word = "Aword";
if (word.StartsWith("A"))
{
// do something
}
You can make a little extension method to pass a list with A, B, and C
public static bool StartsWithAny(this string source, IEnumerable<string> strings)
{
foreach (var valueToCheck in strings)
{
if (source.StartsWith(valueToCheck))
{
return true;
}
}
return false;
}
if (word.StartsWithAny(new List<string>() { "A", "B", "C" }))
{
// do something
}
AND as a bonus, if you want to know what your string starts with, from a list, and do something based on that value:
public static bool StartsWithAny(this string source, IEnumerable<string> strings, out string startsWithValue)
{
startsWithValue = null;
foreach (var valueToCheck in strings)
{
if (source.StartsWith(valueToCheck))
{
startsWithValue = valueToCheck;
return true;
}
}
return false;
}
Usage:
string word = "AWord";
string startsWithValue;
if (word.StartsWithAny(new List<string>() { "a", "b", "c" }, out startsWithValue))
{
switch (startsWithValue)
{
case "A":
// Do Something
break;
// etc.
}
}
You could do something like this to check for a specific character.
public bool StartsWith(string value, string currentChar) {
return value.StartsWith(currentChar, true, null);
}
The StartsWith method has an option to ignore the case. The third parameter is to set the culture. If null, it just uses the current culture. With this method, you can loop through your words, run the check and process the word to highlight that first character as needed.
Assuming the properties you're checking are string types, you can use the String.StartsWith() method.. for example: -
if(item.Title.StartsWith("A"))
{
//do whatever
}
Rinse and repeat
Try the following below. You can do either StartsWith or Substring 0,1 (first letter)
if (Word.Substring(0,1) == "A") {
}
You can simply check the first character:
string word = "AWord"
if (word[0] == 'A')
{
// do something
}
Remember that character comparison is more efficient than string comparison.
To return the first character in a string, use:
Word.Substring(0,1) //where word is a string
You could implement Regular Expressions. They are quite powerful, but when you design your expression it will actually accomplish a task for you.
For example finding a number, letter, word, and etc. it is quite expressive and flexible.
They have a really great tutorial on them here:
An example of such an expression would be:
string input = "Some additional string to compare against.";
Match match = Regex.Match(input, #"\ba\w*\b", RegexOptions.IgnoreCase);
That would find all the items that start with an "a" no matter the case. You find even utilize Lambda and Linq to make them flow even better.
Hopefully that helps.
I need to remove the first (and ONLY the first) occurrence of a string from another string.
Here is an example replacing the string "\\Iteration". This:
ProjectName\\Iteration\\Release1\\Iteration1
would become this:
ProjectName\\Release1\\Iteration1
Here some code that does this:
const string removeString = "\\Iteration";
int index = sourceString.IndexOf(removeString);
int length = removeString.Length;
String startOfString = sourceString.Substring(0, index);
String endOfString = sourceString.Substring(index + length);
String cleanPath = startOfString + endOfString;
That seems like a lot of code.
So my question is this: Is there a cleaner/more readable/more concise way to do this?
int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
? sourceString
: sourceString.Remove(index, removeString.Length);
sourceString.Replace(removeString, "");
string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length);
EDIT: #OregonGhost is right. I myself would break the script up with conditionals to check for such an occurence, but I was operating under the assumption that the strings were given to belong to each other by some requirement. It is possible that business-required exception handling rules are expected to catch this possibility. I myself would use a couple of extra lines to perform conditional checks and also to make it a little more readable for junior developers who may not take the time to read it thoroughly enough.
Wrote a quick TDD Test for this
[TestMethod]
public void Test()
{
var input = #"ProjectName\Iteration\Release1\Iteration1";
var pattern = #"\\Iteration";
var rgx = new Regex(pattern);
var result = rgx.Replace(input, "", 1);
Assert.IsTrue(result.Equals(#"ProjectName\Release1\Iteration1"));
}
rgx.Replace(input, "", 1); says to look in input for anything matching the pattern, with "", 1 time.
You could use an extension method for fun. Typically I don't recommend attaching extension methods to such a general purpose class like string, but like I said this is fun. I borrowed #Luke's answer since there is no point in re-inventing the wheel.
[Test]
public void Should_remove_first_occurrance_of_string() {
var source = "ProjectName\\Iteration\\Release1\\Iteration1";
Assert.That(
source.RemoveFirst("\\Iteration"),
Is.EqualTo("ProjectName\\Release1\\Iteration1"));
}
public static class StringExtensions {
public static string RemoveFirst(this string source, string remove) {
int index = source.IndexOf(remove);
return (index < 0)
? source
: source.Remove(index, remove.Length);
}
}
If you'd like a simple method to resolve this problem. (Can be used as an extension)
See below:
public static string RemoveFirstInstanceOfString(this string value, string removeString)
{
int index = value.IndexOf(removeString, StringComparison.Ordinal);
return index < 0 ? value : value.Remove(index, removeString.Length);
}
Usage:
string valueWithPipes = "| 1 | 2 | 3";
string valueWithoutFirstpipe = valueWithPipes.RemoveFirstInstanceOfString("|");
//Output, valueWithoutFirstpipe = " 1 | 2 | 3";
Inspired by and modified #LukeH's and #Mike's answer.
Don't forget the StringComparison.Ordinal to prevent issues with Culture settings.
https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html
I definitely agree that this is perfect for an extension method, but I think it can be improved a bit.
public static string Remove(this string source, string remove, int firstN)
{
if(firstN <= 0 || string.IsNullOrEmpty(source) || string.IsNullOrEmpty(remove))
{
return source;
}
int index = source.IndexOf(remove);
return index < 0 ? source : source.Remove(index, remove.Length).Remove(remove, --firstN);
}
This does a bit of recursion which is always fun.
Here is a simple unit test as well:
[TestMethod()]
public void RemoveTwiceTest()
{
string source = "look up look up look it up";
string remove = "look";
int firstN = 2;
string expected = " up up look it up";
string actual;
actual = source.Remove(remove, firstN);
Assert.AreEqual(expected, actual);
}