diff --git a/Nuclex.Support (net-4.0).csproj b/Nuclex.Support (net-4.0).csproj index ccbadc4..4fe8546 100644 --- a/Nuclex.Support (net-4.0).csproj +++ b/Nuclex.Support (net-4.0).csproj @@ -223,6 +223,10 @@ CommandLine.cs + + + ParserHelper.cs + PropertyChangedEventArgsHelper.cs diff --git a/Nuclex.Support (xna-4.0-phone7).csproj b/Nuclex.Support (xna-4.0-phone7).csproj index e69b7cb..65fc357 100644 --- a/Nuclex.Support (xna-4.0-phone7).csproj +++ b/Nuclex.Support (xna-4.0-phone7).csproj @@ -254,6 +254,10 @@ CommandLine.cs + + + ParserHelper.cs + PropertyChangedEventArgsHelper.cs diff --git a/Nuclex.Support (xna-4.0-xbox360).csproj b/Nuclex.Support (xna-4.0-xbox360).csproj index 39fab7a..e2fcedb 100644 --- a/Nuclex.Support (xna-4.0-xbox360).csproj +++ b/Nuclex.Support (xna-4.0-xbox360).csproj @@ -265,6 +265,10 @@ CommandLine.cs + + + ParserHelper.cs + PropertyChangedEventArgsHelper.cs diff --git a/Source/Parsing/ParserHelper.Test.cs b/Source/Parsing/ParserHelper.Test.cs new file mode 100644 index 0000000..b929a26 --- /dev/null +++ b/Source/Parsing/ParserHelper.Test.cs @@ -0,0 +1,165 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2013 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +#if UNITTEST + +using NUnit.Framework; + +namespace Nuclex.Support.Parsing { + + /// Verifies that the parser helper methods are correct + [TestFixture] + internal class ParserHelperTest { + + /// Ensures that the SkipSpaces() method can handle null strings + [Test] + public void CanSkipSpacesInNullString() { + int index = 0; + Assert.DoesNotThrow( + delegate() { ParserHelper.SkipSpaces((string)null, ref index); } + ); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipSpaces() method can handle empty strings + [Test] + public void CanSkipSpacesInEmptyString() { + int index = 0; + Assert.DoesNotThrow( + delegate() { ParserHelper.SkipSpaces(string.Empty, ref index); } + ); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipSpaces() method can skip spaces + [Test] + public void SpacesCanBeSkipped() { + int index = 7; + ParserHelper.SkipSpaces(" Test Test ", ref index); + Assert.AreEqual(10, index); + } + + /// Ensures that the SkipNonSpaces() method can handle null strings + [Test] + public void CanSkipNonSpacesInNullString() { + int index = 0; + Assert.DoesNotThrow( + delegate() { ParserHelper.SkipNonSpaces((string)null, ref index); } + ); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipNonSpaces() method can handle empty strings + [Test] + public void CanSkipNonSpacesInEmptyString() { + int index = 0; + Assert.DoesNotThrow( + delegate() { ParserHelper.SkipNonSpaces(string.Empty, ref index); } + ); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipNonSpaces() method can skip non-space characters + [Test] + public void NonSpacesCanBeSkipped() { + int index = 7; + ParserHelper.SkipNonSpaces("Test Test Test", ref index); + Assert.AreEqual(11, index); + } + + /// Ensures that the SkipNumbers() method can handle null strings + [Test] + public void CanSkipNumbersInNullString() { + int index = 0; + Assert.DoesNotThrow( + delegate() { ParserHelper.SkipNumbers((string)null, ref index); } + ); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipNumbers() method can handle empty strings + [Test] + public void CanSkipNumbersInEmptyString() { + int index = 0; + Assert.DoesNotThrow( + delegate() { ParserHelper.SkipNumbers(string.Empty, ref index); } + ); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipNumbers() method can skip numbers + [Test] + public void NumbersCanBeSkipped() { + int index = 6; + ParserHelper.SkipNumbers("123abc456def789", ref index); + Assert.AreEqual(9, index); + } + + /// Ensures that the SkipIntegers() method can handle null strings + [Test] + public void CanSkipIntegersInNullString() { + int index = 0; + Assert.IsFalse(ParserHelper.SkipInteger((string)null, ref index)); + Assert.AreEqual(0, index); + } + + /// Ensures that the SkipNumbers() method can handle empty strings + [Test] + public void CanSkipIntegersInEmptyString() { + int index = 0; + Assert.IsFalse(ParserHelper.SkipInteger(string.Empty, ref index)); + Assert.AreEqual(0, index); + } + + /// Verifies that a prefix alone can not be skipped as an integer + [Test] + public void PrefixAloneIsNotAnInteger() { + int index = 0; + Assert.IsFalse(ParserHelper.SkipInteger("+Test", ref index)); + Assert.AreEqual(0, index); + Assert.IsFalse(ParserHelper.SkipInteger("-", ref index)); + Assert.AreEqual(0, index); + } + + /// Verifies that a prefixed integer can be skipped + [Test] + public void PrefixedIntegersCanBeSkipped() { + int index = 0; + Assert.IsTrue(ParserHelper.SkipInteger("+123", ref index)); + Assert.AreEqual(4, index); + } + + /// Verifies that an integer without a prefix can be skipped + [Test] + public void PlainIntegersCanBeSkipped() { + int index = 0; + Assert.IsTrue(ParserHelper.SkipInteger("12345", ref index)); + Assert.AreEqual(5, index); + } + + } + +} // namespace Nuclex.Support.Parsing + +#endif // UNITTEST diff --git a/Source/Parsing/ParserHelper.cs b/Source/Parsing/ParserHelper.cs new file mode 100644 index 0000000..333b4cf --- /dev/null +++ b/Source/Parsing/ParserHelper.cs @@ -0,0 +1,120 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2013 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; + +namespace Nuclex.Support.Parsing { + + /// Provides helper methods for parsers + public class ParserHelper { + + /// Advances the index past any whitespace in the string + /// String which is being indexed + /// Index that will be advanced + public static void SkipSpaces(string text, ref int index) { + if(text == null) { + return; + } + + int length = text.Length; + while(index < length) { + if(!char.IsWhiteSpace(text, index)) { + break; + } + + ++index; + } + } + + /// Advances the index to the next whitespace in the string + /// String which is being indexed + /// Index that will be advanced + public static void SkipNonSpaces(string text, ref int index) { + if(text == null) { + return; + } + + int length = text.Length; + while(index < length) { + if(char.IsWhiteSpace(text, index)) { + break; + } + + ++index; + } + } + + /// Advances the index to the next character that isn't numeric + /// String which is being indexed + /// Index that will be advanced + public static void SkipNumbers(string text, ref int index) { + if(text == null) { + return; + } + + int length = text.Length; + while(index < length) { + if(!char.IsNumber(text, index)) { + break; + } + + ++index; + } + } + + /// Skips an integer in the provided string + /// String in which an integer will be skipped + /// Index at which the integer begins + /// True if an integer was found and skipped, otherwise false + public static bool SkipInteger(string text, ref int index) { + if(text == null) { + return false; + } + + int length = text.Length; + if(index >= length) { + return false; + } + + // If the number begins with a minus or plus sign, skip over the sign + int nextIndex; + if((text[index] == '-') || (text[index] == '+')) { + nextIndex = index + 1; + + SkipNumbers(text, ref nextIndex); + if(nextIndex == (index + 1)) { + return false; + } + } else { + nextIndex = index; + + SkipNumbers(text, ref nextIndex); + if(nextIndex == index) { + return false; + } + } + + index = nextIndex; + return true; + } + + } + +} // namespace Nuclex.Support.Parsing