c# contains word exception number - c#

I need to search a string and see if it contains "<addnum(x)>"
I have used .contains on the other words that i searched for and the easiest way i could think for is you somehow could make exception for numbers or do you need to use another code for that?
My code this far.
public List<string> arguments = new List<string>();
public void Custom_naming(string name_code)
{
arguments.Add("Changing the name to " + name_code); // Sets the new name.
if( name_code.Contains("<addnum>") )
{
Add_number();
}
if (name_code.Contains("<addnum(x)>"))
{// X = any number.
}
}
private void Add_number()
{
arguments.Add("Replaces all <addnum> with a number");
}
private void Add_number(int zeros)
{
arguments.Add("Replaces all <addnumxx> with a number with lentgh of");
}

You probably need to use a regular expression:
var match = Regex.Match(name_code, #"<addnum(?:\((\d+)\))?>");
if (match.Success)
{
int zeros;
if (int.TryParse(match.Groups[1].Value, out zeros))
{
Add_number(zeros);
}
else
{
Add_number();
}
}
This will return invoke the appropriate Add_number method if name_code contains <addnum> or anything like <addnum(123)>.
If there could possibly be more than one such in name_code, e.g. <addnum(1)><addnum(2)>, you'll want to use a loop to analyze each match, like this:
var matches = Regex.Matches(name_code, #"<addnum(?:\((\d+)\))?>");
foreach(var match in matches)
{
int zeros;
if (int.TryParse(match.Groups[1].Value, out zeros))
{
Add_number(zeros);
}
else
{
Add_number();
}
}

Use regular expression:
string s = "Foo <addnum(8)> bar.";
var contains = Regex.IsMatch(s, #"<addnum\(\d+\)>");
If you want also extract number:
string s = "Foo <addnum(42)> bar.";
var match = Regex.Match(s, #"<addnum\((\d+)\)>");
if (match.Success)
{
// assume you have valid integer number
var number = Int32.Parse(match.Groups[1].Value);
}

Related

Increment string if exists

I need a piece of code that increments end of string in "[]" brackets, but I got headache with that.
Thing is, if name "test" exists in given collection, algorithm should return test_[0], if both exists then "test_[1]" etc. That works so far. But when I tried to pass as currentName value "test_[something]" algorithm creates something like test_[0]_[0], test_[0]_[1] instead of test_[somenthing+someNumber]. Does anyone know the way to change this behavior?
// test test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
if (existingNames.Any(n => n.Equals(currentName)))
{
do
{
if (!currentName.EndsWith($"({iteration})"))
{
currentName = $"{currentName}_[{++iteration}]";
}
}
while (existingNames.Any(n => n.Equals(currentName)));
}
return currentName;
}
EDIT :
The best solution so far is that(I can bet that I've seen it here, but someone had to delete)
public static void Main()
{
var currentOriginal = "test";
var existingNamesOriginal = new[] { "test", "test_[2]", "test_[3]" };
string outputOriginal = GetDistinctNameFromSO(currentOriginal, existingNamesOriginal);
Console.WriteLine("original : " + outputOriginal);
Console.ReadLine();
}
protected static string GetDistinctNameFromSO(string currentName,
IEnumerable<string> existingNames)
{
if (null == currentName)
throw new ArgumentNullException(nameof(currentName));
else if (null == existingNames)
throw new ArgumentNullException(nameof(existingNames));
string pattern = $#"^{Regex.Escape(currentName)}(?:_\[(?<Number>[0-9]+)\])?$";
Regex regex = new Regex(pattern);
var next = existingNames
.Select(item => regex.Match(item))
.Where(match => match.Success)
.Select(match => string.IsNullOrEmpty(match.Groups["Number"].Value)
? 1
: int.Parse(match.Groups["Number"].Value))
.DefaultIfEmpty()
.Max() + 1;
if (next == 1)
return currentName; // No existingNames - return currentName
else
return $"{currentName}_[{next}]";
}
For given "test" string it returns "test_[4]" which is excellent, but if given string is let's say "test_[2]" it should also return "test_[4]"(string with given pattern with first free number), but it returns "test_[2]_[2]" instead.
I will try answer with minimal adjustments to your code:
Use square brackets to check if name exists
Use a local variable to prevent adding [0] over and over
increment iteration on every do/while loop
if the result, should never be "test", exclude it from the existing results
The result looks like (not tested, but this should get you on your way):
// test test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
// Use a different variable this will prevent you from adding [0] again and again
var result = currentName;
if (existingNames.Where(s => s != currentName).Any(n => n.Equals(result)))
{
do
{
// Use square brackets
if (!result .EndsWith($"[{iteration}]"))
{
result = $"{currentName}_[{iteration}]";
}
iteration++; // Increment with every step
}
while (existingNames.Any(n => n.Equals(result)));
}
return result;
}
Here's a simpler rewrite:
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
var name = currentName;
while(existingNames.Contains(name))
{
name = currentName + "_[" + (iteration++) + "]";
}
return name;
}
Tests:
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[2]", "test_[3]"}).Dump();//Out: test_[1]
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[1]", "test_[2]", "test_[3]"}).Dump();//Out: test_[4]
GetDistinctName2("test", new List<string> {}).Dump();//Out: test
Your description of your problem and your code and completely different. Here will increment a number inside the square brackets without appending additional text.
The change from the initial code addresses a problem mentioned in the question about including text inside the square brackets with a number. Below you can replace something with other text.
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
string nextName = currentName;
while (existingNames.Contains(nextName))
{
nextName = $"{currentName}_[something{iteration}]";
iteration++;
}
return nextName;
}
C# interactive shell example:
> GetDistinctName2("test", new List<string>() { "test", "test_[something0]", "test_[something1]"})
"test_[something2]"

How to add numbers in a mixed string C#

example = "I-000146.22.43.24"
In the example, I need to validate that the last number after the period isnt over 9. Currently is 24 and thats not valid.
01-08 is valid and anything over that isnt.
How can I add logic to check for this?
One solution would be to use Regex. The regex pattern would be something like this:
^.+\.(0?[0-8])$
Regex demo.
C# example:
string pattern = #"^.+\.(0?[0-8])$";
string[] inputs = new [] { "I-000146.22.43.24", "I-000146.22.43.09",
"I-000146.22.43.08", "xxxxxxx.07" };
foreach (string input in inputs)
{
Match match = Regex.Match(input, pattern);
if (match.Success)
Console.WriteLine($"The input is valid. Last number is '{match.Groups[1].Value}'.");
else
Console.WriteLine("The input is not valid.");
}
Output:
The input is not valid.
The input is not valid.
The input is valid. Last number is '08'.
The input is valid. Last number is '07'.
Try it online.
You could use Linq:
using System;
using System.Linq;
class MainClass {
public static void Main (string[] args) {
String[] tests = new string[3] {"I-000146.22.43.24", "I-000146.22.43.9", "I-000146.22.43.a"};
foreach (string test in tests) {
Console.WriteLine ($"{test} is a valid string: {isValidString (test)}");
}
}
private static bool isValidString (string str) {
var lastNumString = str.Split ('.').Last();
return isSingleDigit (lastNumString);
}
private static bool isSingleDigit (string numString) {
int number;
bool success = Int32.TryParse (numString, out number);
if (success) {
return number >= 0 && number <= 9;
}
return success;
}
}
Output:
I-000146.22.43.24 is a valid string: False
I-000146.22.43.9 is a valid string: True
I-000146.22.43.a is a valid string: False

advanced regex.replace handling

I am using a Regex with a MatchEvaluator delegate to process a format string, e.g. "Time: %t, bytes: %b" would replace the "%t" with a time stamp, and the "%b" with a bytes count. Needless to say, there are loads of other options!
To do this, I use:
Regex regex = new Regex("%((?<BytesCompleted>b)|(?<BytesRemaining>B)|(?<TimeStamp>t))");
string s = "%bhello%t(HH:MM:SS)%P";
string r = regex.Replace(s, new MatchEvaluator(ReplaceMatch));
and
string ReplaceMatch(Match m)
{
... Handle the match replacement.
}
What would be nice is if I could use the Regex group name (or even the number, I'm not that fussy) in the delegate instead of comparing against the raw match to find out which match this is:
string ReplaceMatch(Match m)
{
...
case "%t":
...
case "%b";
...
}
Is pretty ugly; I would like to use
string ReplaceMatch(Match m)
{
...
case "BytesCompleted":
...
case "TimeStamp":
...
}
I can't see anything obvious via the debugger, or via google. Any ideas?
It would be nice to be able to use the group name in the switch; unfortunately the Group object doesn't have a Name property (and neither does its base class Capture) so the best you'll be able to do is the following:
string ReplaceMatch(Match m)
{
if (m.Groups["BytesCompleted"].Success) // ...
else if (m.Groups["BytesRemaining"].Success) // ...
// ...
}
You can use Regex.GroupNameFromNumber instance method, and this unfortunately means that the match-evaluator method requires a reference to the Regex object:
string ReplaceMatch(Match m)
{
for (int i = 0; i < m.Groups.Count; i++)
{
string groupName = _regex.GroupNameFromNumber(i);
switch (groupName)
{
case "BytesCompleted":
// do something
break;
case "BytesRemaining":
// do somehting else
break;
...
}
}
...
}
Here I assumed that the Regex object is accessible through the _regex variable.
We'll need to combine both Sina's and james' answers. We need to enumerate the groups to get the index and check for group success. Then we use the index to get group name. I have expanded a bit into a self-explaining test that uses dictionary to replace matched substrings. With a little more support for group names in the framework, this would have been so much easier.
Also see another answer that might work for you: https://stackoverflow.com/a/1381163/481812
[Test]
public void ExploreRxReplace()
{
var txt = " ABC XYZ DEF ";
var exp = " *** XYZ xxx ";
var rx = new Regex(#"\s*(?<abc>ABC)\s*|\s*(?<def>DEF)\s*");
var data = new Dictionary<string, string>() { { "abc", "***" }, { "def", "xxx" } };
var txt2 = rx.Replace(txt, (m) =>
{
var sb = new StringBuilder();
var pos = m.Index;
for (var idx = 1; idx < m.Groups.Count; idx++)
{
var group = m.Groups[idx];
if (!group.Success)
{
// ignore non-matching group
continue;
}
var name = rx.GroupNameFromNumber(idx);
// append what's before
sb.Append(txt.Substring(pos, group.Index - pos));
string value = null;
if (group.Success && data.TryGetValue(name, out value))
{
// append dictionary value
sb.Append(value);
}
else
{
// append group value
sb.Append(group.Value);
}
pos = group.Index + group.Length;
}
// append what's after
sb.Append(txt.Substring(pos, m.Index + m.Length - pos));
return sb.ToString();
});
Assert.AreEqual(exp, txt2);
}

Find a substring, replace a substring according the case

What's the easiest and fastest way to find a sub-string(template) in a string and replace it with something else following the template's letter case (if all lower case - replace with lowercase, if all upper case - replace with uppercase, if begins with uppercase and so on...)
so if the substring is in curly braces
"{template}" becomes "replaced content"
"{TEMPLATE}" becomes "REPLACED CONTENT" and
"{Template}" becomes "Replaced content" but
"{tEMPLATE}" becomes "rEPLACED CONTENT"
Well, you could use regular expressions and a match evaluator callback like this:
regex = new Regex(#"\{(?<value>.*?)\}",
RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
string replacedText = regex.Replace(<text>,
new MatchEvaluator(this.EvaluateMatchCallback));
And your evaluator callback would do something like this:
private string EvaluateMatchCallback(Match match) {
string templateInsert = match.Groups["value"].Value;
// or whatever
string replacedText = GetReplacementTextBasedOnTemplateValue(templateInsert);
return replacedText;
}
Once you get the regex match value you can just do a case-sensitive comparison and return the correct replacement value.
EDIT I sort of assumed you were trying to find the placeholders in a block of text rather than worry about the casing per se, if your pattern is valid all the time then you can just check the first two characters of the placeholder itself and that will tell you the casing you need to use in the replacement expression:
string foo = "teMPLATE";
if (char.IsLower(foo[0])) {
if (char.IsLower(foo[1])) {
// first lower and second lower
}
else {
// first lower and second upper
}
}
else {
if (char.IsLower(foo[1])) {
// first upper and second lower
}
else {
// first upper and second upper
}
}
I would still use a regular expression to match the replacement placeholder, but that's just me.
You can check the case of the first two letters of the placeholder and choose one of the four case transforming strategies for the inserted text.
public static string Convert(string input, bool firstIsUpper, bool restIsUpper)
{
string firstLetter = input.Substring(0, 1);
firstLetter = firstIsUpper ? firstLetter.ToUpper() : firstLetter.ToLower();
string rest = input.Substring(1);
rest = restIsUpper ? rest.ToUpper() : rest.ToLower();
return firstLetter + rest;
}
public static string Replace(string input, Dictionary<string, string> valueMap)
{
var ms = Regex.Matches(input, "{(\\w+?)}");
int i = 0;
var sb = new StringBuilder();
for (int j = 0; j < ms.Count; j++)
{
string pattern = ms[j].Groups[1].Value;
string key = pattern.ToLower();
bool firstIsUpper = char.IsUpper(pattern[0]);
bool restIsUpper = char.IsUpper(pattern[1]);
sb.Append(input.Substring(i, ms[j].Index - i));
sb.Append(Convert(valueMap[key], firstIsUpper, restIsUpper));
i = ms[j].Index + ms[j].Length;
}
return sb.ToString();
}
public static void DoStuff()
{
Console.WriteLine(Replace("--- {aAA} --- {AAA} --- {Aaa}", new Dictionary<string,string> {{"aaa", "replacement"}}));
}
Ended up doing that:
public static string ReplaceWithTemplate(this string original, string pattern, string replacement)
{
var template = Regex.Match(original, pattern, RegexOptions.IgnoreCase).Value.Remove(0, 1);
template = template.Remove(template.Length - 1);
var chars = new List<char>();
var isLetter = false;
for (int i = 0; i < replacement.Length; i++)
{
if (i < (template.Length)) isLetter = Char.IsUpper(template[i]);
chars.Add(Convert.ToChar(
isLetter ? Char.ToUpper(replacement[i])
: Char.ToLower(replacement[i])));
}
return new string(chars.ToArray());
}

How to check if a string contains any of the elements in an string array?

I'm trying to implement a simple search function. I have a string array which contains all words which was typed in from the user to search. And I have another string which contains data like User Name, content... So what I want to do is to check is Name contains any of the elements in the search or String array. Right now I have a loop which checks one word at a time and concatenates the result in an IEnumerable.
Does anyone know a faster way of doing this search? Like String.ContainsAny(Search[])
Try this:
Search.Any(p => name.Contains(p))
using System.Linq;
string[] searchItems = ...
string input = "This is the input text";
// Check whether at least one match found
bool matchFound = input.Any(w => input.Contains(w));
// Count all matches
int matchesCount = input.Where(w => input.Contains(w))
.Count();
string[] searchItems = ...;
string[] userNames = ...;
var matches = userNames.Intersect(searchItems);
You can find more about the intersect method here
you can do like this...
return array.Any(s => s.Equals(myString))
or try like this....
string stringToCheck = "text1";
string[] stringArray = { "text1", "testtest", "test1test2", "test2text1" };
foreach (string x in stringArray)
{
if (x.Contains(stringToCheck))
{
// Process...
}
}
or Something like this
string stringToCheck = "text1text2text3";
string[] stringArray = new string[] { "text1" };
if (Array.Exists<string>(stringArray, (Predicate<string>)delegate(string s) {
return stringToCheck.IndexOf(s, StringComparison.OrdinalIgnoreCase) > -1; })) {
Console.WriteLine("Found!");
}
Two solutions to this problem for example:
Solution 1
private void findDateColumn() {
string stringToCheck = "date";
int stringToCheckIndex = -1;
string elementInArray = "Not Defined or Not Found";
if (Array.Exists<string> (headers, (Predicate<string>) delegate (string s)
{
stringToCheckIndex = s.IndexOf (stringToCheck,StringComparison.OrdinalIgnoreCase);
elementInArray = s;
return stringToCheckIndex > -1;
}))
{
dateColTitle.Text = elementInArray; //a textbox to show the output
}
}
Solution 2
I'm using #Lev answer, which seems simpler and shorter plus giving the same result:
private void setDateColumnTitle ()
{
dateColTitle.Text = "Not Defined or Not Found";
var match = headers.FirstOrDefault(c => c.IndexOf("date", StringComparison.OrdinalIgnoreCase) > -1);
if (match!=null)
dateColTitle.Text = match;
}

Categories

Resources