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