4
\$\begingroup\$

The basic idea is not to allow the same text and add +1 at the end.

Imagine that I have a datagrid (WPF) with names, and every time I click the add button, I will put a new name on the list automatically by running this method to ensure that no two names are alike.

My standard used: if there is repeated text, add to the end "(" + count + ")", similar to Windows Explorer.

Are there ways to make this using LINQ or Regex?

private void Test()
{
 var result = CreateText("t", new string[] { "t", "t(1)", "t(2)", "t(3)", "t(4)", "t(5)", "t(6)", "t(7)", "t(8)", "t(9)", "t(10)" });
 Assert.IsTrue(result == "t(11)");
}
public static String CreateText(string newText, String[] texts)
{
 int addCount = 0;
 foreach (String text in texts)
 {
 if (text.IndexOf(newText) == 0)
 {
 if (text == newText && addCount == 0)
 {
 addCount = 1;
 continue;
 }
 else
 {
 if (text.LastIndexOf('(') == newText.Length && text.LastIndexOf(')') == text.Length - 1)
 {
 try
 {
 var initial = text.LastIndexOf('(') + 1;
 var size = text.LastIndexOf(')') - initial;
 int count = Int16.Parse(text.Substring(initial, size));
 if (addCount <= count)
 {
 addCount = count + 1;
 }
 }
 catch (Exception)
 {
 addCount = 0;
 }
 }
 }
 }
 }
 if (addCount > 0)
 {
 newText += "(" + addCount + ")";
 }
 return newText;
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Nov 13, 2012 at 23:44
\$\endgroup\$
2
  • \$\begingroup\$ It looks kind of under specified to me. What is the output of {"t(1)", "a(2)"}? {"t(t(1))", "T(42)"}? {"hello","world"}? Your test suggests you didn't clarify to yourself what are the requirements here. \$\endgroup\$ Commented Nov 14, 2012 at 7:56
  • \$\begingroup\$ @avip sorry, I will clarify the operation \$\endgroup\$ Commented Nov 14, 2012 at 10:01

3 Answers 3

4
\$\begingroup\$

Here is shorter method with regex

 private static String CreateText(string textIdentifier, IEnumerable<string> texts)
 {
 const int defaultNumber = 1;
 Regex regex = new Regex(@"\(\s*(?<num>\d+)\s*\)");
 var numbers = 
 texts.Select(p => p.Trim()).Where(p => p.StartsWith(textIdentifier))
 .Select(str => { var m = regex.Match(str); return m.Success ? int.Parse(m.Groups["num"].Value) + 1 : defaultNumber; });
 int max = numbers.Any() ? numbers.Max() : 0;
 return max == 0 ? textIdentifier : string.Format("{0}({1})", textIdentifier, max);
 }

+1 to @dreza for tests ;)

answered Nov 14, 2012 at 10:48
\$\endgroup\$
0
3
\$\begingroup\$

There might be one problem with @Danil code. Although it passes the unit test that was provided what if the array contained values of "t", "t(1)", "t(2)", "t(3)", "t(4)", "t(5)", "t(6)", "t(7)", "t(8)", "t(9)", "test(10)"

In this case I would think you would want the return value to be t(10). Maybe the above scenerio is not possible, but if it is, here is a revision to @Danil code which would handle it.

private static String CreateText(string textIdentifier, IEnumerable<string> texts)
{
 const int defaultNumber = 0;
 Regex regex = new Regex("^" + textIdentifier + @"\(\s*(?<num>\d+)\s*\)");
 var max = 
 texts.Select(p => p.Trim())
 .Select(str => { var m = regex.Match(str); return m.Success ? int.Parse(m.Groups["num"].Value) + 1 : defaultNumber; })
 .Max();
 return max == 0 ? textIdentifier : string.Format("{0}({1})", textIdentifier, max);
}
answered Nov 14, 2012 at 14:18
\$\endgroup\$
2
  • \$\begingroup\$ Yep, you are right. I've missed it. \$\endgroup\$ Commented Nov 14, 2012 at 14:58
  • \$\begingroup\$ worked well in tests. but looking now, this code does not meet one of the requirements. it still lets texts exactly alike. \$\endgroup\$ Commented Nov 26, 2012 at 16:21
2
\$\begingroup\$

Here's a way. Not fully Linq but using a little bit in the for loop. Also passes a few more unit tests than your original.

[EDIT]: After re-reading your question and some comments by other reviewers I added a few more unit tests and low and behold my original answer broke. So I've re-worked it and now made it even more complicated :) but passes the new unit tests I put in 10,11 and 12.

Whether your code needs to pass thoses tests or not though I'll leave that for you to decide.

As for optimization. I haven't profiled it so can't comment there.

 [TestMethod]
 public void Test()
 {
 var result = CreateText("t", new string[] { "t", "t(1)", "t(2)", "t(3)", "t(4)", "t(5)", "t(6)", "t(7)", "t(8)", "t(9)", "t(10)" });
 Assert.IsTrue(result == "t(11)");
 }
 [TestMethod]
 public void Test1()
 {
 var result = CreateText("t", new string[] { "t" });
 Assert.AreEqual("t(1)", result);
 }
 [TestMethod]
 public void Test2()
 {
 var result = CreateText("t", new string[] { "t", "t(4)", "t(2)", "z(3)", "t (45)", "t5)", "t(10)", "t(12)", "t( 89 ),ttt, t, t(23), t(8, t(we", "t( 89 )", "t(23)", "t(8", "t(we" });
 Assert.AreEqual("t(90)", result);
 }
 [TestMethod]
 public void Test3()
 {
 var result = CreateText("t", new string[] { });
 Assert.IsTrue(result == "t");
 }
 [TestMethod]
 public void Test4()
 {
 var result = CreateText("z", new string[] { "t(1)" });
 Assert.AreEqual("z", result);
 }
 [TestMethod]
 public void Test5()
 {
 var result = CreateText("z", new string[] { "t(-1)" });
 Assert.AreEqual("z", result);
 }
 [TestMethod]
 public void Test6()
 {
 var result = CreateText("t", new string[] { " t(0)" });
 Assert.AreEqual("t(1)", result);
 }
 [TestMethod]
 public void Test7()
 {
 var result = CreateText("t", new string[] { " t(9) " });
 Assert.AreEqual("t(10)", result);
 }
 [TestMethod]
 public void Test8()
 {
 var result = CreateText("t", new string[] { "t(1)", "t(2)", "t(3)", "t(4)", "t(5)", "t(6)", "t(7)", "t(8)", "t(9)", "test(10)" });
 Assert.AreEqual("t(10)", result);
 }
 [TestMethod]
 public void Test9()
 {
 var result = CreateText("t", new string[] { "t(1)", "t(2)", "t(3)", "t(4)", "t(5)", "t(6)", "t(7)", "t(8)", "t (9)", "test(10)" });
 Assert.AreEqual("t(10)", result);
 }
 [TestMethod]
 public void Test10()
 {
 var result = CreateText("t", new string[] { "t(1)", "t(2)", "t(3)", "t(4)", "t(5)", "t(6)", "t(7)", "t t(8)", "t (9)", "test(10)" });
 Assert.AreEqual("t(10)", result);
 }
 [TestMethod]
 public void Test11()
 {
 var result = CreateText("t", new string[] { "t(1)", "t(2)", "t(3)", "t(4)", "t((((24)", "ttt(22)", "t(7)", "t t(8)", "t (9)", "t(1)" });
 Assert.AreEqual("t(10)", result);
 }
 [TestMethod]
 public void Test12()
 {
 var result = CreateText("t", new string[] { "t(1)", "t(2)", "t(3)", "t(4)", "t((((24)", "ttt(22)", "t(29)) ))", "t t(8)", "t (9)", "t(1)" });
 Assert.AreEqual("t(30)", result);
 }
 private static String CreateText(string textIdentifier, IEnumerable<string> texts)
 {
 const char startDeliminator = '(';
 const char endDeliminator = ')';
 int nextCount = 0;
 foreach (String text in texts.Select(p => p.Trim()).Where(p => p.StartsWith(textIdentifier)))
 {
 short addCount = 0;
 var startDelminatorIndex = text.LastIndexOf(startDeliminator);
 // there must be at least one start deliminator
 if (startDelminatorIndex >= 0)
 {
 var endDeliminatorIndex = text.IndexOf(endDeliminator, startDelminatorIndex);
 var textName = text.Substring(0, startDelminatorIndex).Trim();
 if (textName.Equals(textIdentifier, StringComparison.CurrentCultureIgnoreCase))
 {
 if (endDeliminatorIndex > startDelminatorIndex)
 {
 startDelminatorIndex++; // get past the (
 var size = endDeliminatorIndex - startDelminatorIndex;
 Int16.TryParse(text.Substring(startDelminatorIndex, size).Trim(), out addCount);
 }
 }
 }
 nextCount = Math.Max(nextCount, addCount + 1);
 }
 return nextCount == 0 ? textIdentifier : string.Format("{0}({1})", textIdentifier, nextCount);
 }
answered Nov 14, 2012 at 0:33
\$\endgroup\$
2
  • \$\begingroup\$ good idea to use the linq before the loop, although I think that horrible "p.Trim()" \$\endgroup\$ Commented Nov 14, 2012 at 0:48
  • \$\begingroup\$ Yeah, unless you don't need to worry about whitespace i.e. assume it's already trimmed you could remove it. However without Test7 and Test6 don't pass. \$\endgroup\$ Commented Nov 14, 2012 at 1:11

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.