Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's some code that uses regular expressions.</p> <p>Note that the issue raised by Bart in the comments to your question, ie. "How do you handle 1+++5", is not handled at all.</p> <p>To fix that, unless your code is already out in the wild and not subject to change of behaviour, I would suggest you change your syntax to the following:</p> <ul> <li>use .. to denote ranges</li> <li>allow both + and - for numbers, for positive and negative numbers</li> <li>use comma and/or semicolon to separate distinct numbers or ranges</li> <li>allow whitespace</li> </ul> <p>Look at the difference between the two following strings:</p> <ul> <li>1++7+10++15+20+30++</li> <li>1..7, 10..15, 20, 30..</li> </ul> <p>The second string is much easier to parse, and much easier to read.</p> <p>It would also remove all ambiguity:</p> <ul> <li>1+++5 = 1++ + 5 = 1.., 5</li> <li>1+++5 = 1 + ++5 = 1, ..5</li> </ul> <p>There's no way to parse wrong the second syntax.</p> <hr> <p>Anyway, here's my code. Basically it works by adding four regex patterns for the four types of patterns:</p> <ul> <li>num</li> <li>num++</li> <li>++num</li> <li>num++num</li> </ul> <p>For "num", it will handle negative numbers with a leading minus sign, and one or more digits. It does not, for obvious reasons, handle the plus sign as part of the number.</p> <p>I've interpreted "and up" to mean "up to Int32.MaxValue" and same for down to Int32.MinValue.</p> <pre><code>public class Range { public readonly Int32 From; public readonly Int32 To; public Range(Int32 from, Int32 to) { From = from; To = to; } public override string ToString() { if (From == To) return From.ToString(); else if (From == Int32.MinValue) return String.Format("++{0}", To); else if (To == Int32.MaxValue) return String.Format("{0}++", From); else return String.Format("{0}++{1}", From, To); } } public static class RangeSplitter { public static Range[] Split(String s) { if (s == null) throw new ArgumentNullException("s"); String[] parts = new Regex(@"(?&lt;!\+)\+(?!\+)").Split(s); List&lt;Range&gt; result = new List&lt;Range&gt;(); var patterns = new Dictionary&lt;Regex, Action&lt;Int32[]&gt;&gt;(); patterns.Add(new Regex(@"^(-?\d+)$"), values =&gt; result.Add(new Range(values[0], values[0]))); patterns.Add(new Regex(@"^(-?\d+)\+\+$"), values =&gt; result.Add(new Range(values[0], Int32.MaxValue))); patterns.Add(new Regex(@"^\+\+(-?\d+)$"), values =&gt; result.Add(new Range(Int32.MinValue, values[0]))); patterns.Add(new Regex(@"^(-?\d+)\+\+(-?\d+)$"), values =&gt; result.Add(new Range(values[0], values[1]))); foreach (String part in parts) { foreach (var kvp in patterns) { Match ma = kvp.Key.Match(part); if (ma.Success) { Int32[] values = ma.Groups .OfType&lt;Group&gt;() .Skip(1) // group 0 is the entire match .Select(g =&gt; Int32.Parse(g.Value)) .ToArray(); kvp.Value(values); } } } return result.ToArray(); } } </code></pre> <p>Unit-tests:</p> <pre><code>[TestFixture] public class RangeSplitterTests { [Test] public void Split_NullString_ThrowsArgumentNullException() { Assert.Throws&lt;ArgumentNullException&gt;(() =&gt; { var result = RangeSplitter.Split(null); }); } [Test] public void Split_EmptyString_ReturnsEmptyArray() { Range[] result = RangeSplitter.Split(String.Empty); Assert.That(result.Length, Is.EqualTo(0)); } [TestCase(01, "++7", Int32.MinValue, 7)] [TestCase(02, "7", 7, 7)] [TestCase(03, "7++", 7, Int32.MaxValue)] [TestCase(04, "1++7", 1, 7)] public void Split_SinglePatterns_ProducesExpectedRangeBounds( Int32 testIndex, String input, Int32 expectedLower, Int32 expectedUpper) { Range[] result = RangeSplitter.Split(input); Assert.That(result.Length, Is.EqualTo(1)); Assert.That(result[0].From, Is.EqualTo(expectedLower)); Assert.That(result[0].To, Is.EqualTo(expectedUpper)); } [TestCase(01, "++7")] [TestCase(02, "7++")] [TestCase(03, "1++7")] [TestCase(04, "1+7")] [TestCase(05, "1++7+10++15+20+30++")] public void Split_ExamplesFromQuestion_ProducesCorrectResults( Int32 testIndex, String input) { Range[] ranges = RangeSplitter.Split(input); String rangesAsString = String.Join("+", ranges.Select(r =&gt; r.ToString()).ToArray()); Assert.That(rangesAsString, Is.EqualTo(input)); } [TestCase(01, 10, 10, "10")] [TestCase(02, 1, 10, "1++10")] [TestCase(03, Int32.MinValue, 10, "++10")] [TestCase(04, 10, Int32.MaxValue, "10++")] public void RangeToString_Patterns_ProducesCorrectResults( Int32 testIndex, Int32 lower, Int32 upper, String expected) { Range range = new Range(lower, upper); Assert.That(range.ToString(), Is.EqualTo(expected)); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload