diff --git a/Nuclex.Support (x86).csproj b/Nuclex.Support (x86).csproj
index 4f22580..0ba44f2 100644
--- a/Nuclex.Support (x86).csproj
+++ b/Nuclex.Support (x86).csproj
@@ -178,7 +178,10 @@
-
+
+ StringHelper.cs
+
+
diff --git a/Source/StringHelper.Test.cs b/Source/StringHelper.Test.cs
index 5e18edc..ce9a8c4 100644
--- a/Source/StringHelper.Test.cs
+++ b/Source/StringHelper.Test.cs
@@ -30,8 +30,61 @@ namespace Nuclex.Support {
/// Unit Test for the string helper class
[TestFixture]
- public class PathHelperTest {
+ public class StringHelperTest {
+ ///
+ /// Verifies that the IndexNotOfAny() method works identical to the framework's
+ /// implementation of the IndexOfAny() method, only inverted.
+ ///
+ [Test]
+ public void TestIndexNotOfAny() {
+ string positive = "xxxxxOOOOO";
+ string negative = "OOOOOxxxxx";
+
+ Assert.AreEqual(
+ positive.IndexOfAny(new char[] { 'O' }),
+ StringHelper.IndexNotOfAny(negative, new char[] { 'O' })
+ );
+ }
+
+ ///
+ /// Verifies that the LastIndexNotOfAny() method works identical to the framework's
+ /// implementation of the LastIndexOfAny() method, only inverted.
+ ///
+ [Test]
+ public void TestLastIndexNotOfAny() {
+ string positive = "xxxxxOOOOO";
+ string negative = "OOOOOxxxxx";
+
+ Assert.AreEqual(
+ positive.LastIndexOfAny(new char[] { 'x' }),
+ StringHelper.LastIndexNotOfAny(negative, new char[] { 'x' })
+ );
+ }
+
+ ///
+ /// Verifies that the IndexNotOfAny() method works with multiple characters
+ ///
+ [Test]
+ public void TestMultipleCharIndexNotOfAny() {
+ string haystack = "0123456789";
+
+ Assert.AreEqual(
+ 5, StringHelper.IndexNotOfAny(haystack, new char[] { '4', '3', '2', '1', '0' })
+ );
+ }
+
+ ///
+ /// Verifies that the IndexNotOfAny() method works with multiple characters
+ ///
+ [Test]
+ public void TestMultipleCharLastIndexNotOfAny() {
+ string haystack = "0123456789";
+
+ Assert.AreEqual(
+ 4, StringHelper.LastIndexNotOfAny(haystack, new char[] { '9', '8', '7', '6', '5' })
+ );
+ }
}
diff --git a/Source/StringHelper.cs b/Source/StringHelper.cs
index 75d60d7..ca39411 100644
--- a/Source/StringHelper.cs
+++ b/Source/StringHelper.cs
@@ -83,10 +83,9 @@ namespace Nuclex.Support {
while(startIndex < count) {
char character = haystack[startIndex];
- for(int anyIndex = 0; anyIndex < anyLength; ++anyIndex) {
- if(character != anyNotOf[anyIndex]) {
- return startIndex;
- }
+ int index = Array.IndexOf(anyNotOf, character, 0, anyLength);
+ if(index == -1) {
+ return startIndex;
}
++startIndex;
@@ -152,10 +151,9 @@ namespace Nuclex.Support {
while(startIndex > count) {
char character = haystack[startIndex];
- for(int anyIndex = 0; anyIndex < anyLength; ++anyIndex) {
- if(character != anyNotOf[anyIndex]) {
- return startIndex;
- }
+ int index = Array.IndexOf(anyNotOf, character, 0, anyLength);
+ if(index == -1) {
+ return startIndex;
}
--startIndex;
diff --git a/Source/StringSegment.cs b/Source/StringSegment.cs
new file mode 100644
index 0000000..bfb57ae
--- /dev/null
+++ b/Source/StringSegment.cs
@@ -0,0 +1,197 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2008 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.Runtime.InteropServices;
+
+namespace Nuclex.Support {
+
+ /// Delimits a section of a string
+ [Serializable, StructLayout(LayoutKind.Sequential)]
+ internal struct StringSegment {
+
+ ///
+ /// Initializes a new instance of the class that delimits
+ /// all the elements in the specified string
+ ///
+ /// String that will be wrapped
+ /// String is null
+ public StringSegment(string text) {
+ if(text == null) {
+ throw new ArgumentNullException("text");
+ }
+
+ this.text = text;
+ this.offset = 0;
+ this.count = text.Length;
+ }
+
+ ///
+ /// Initializes a new instance of the class that delimits
+ /// the specified range of the elements in the specified string
+ ///
+ /// The string containing the range of elements to delimit
+ /// The zero-based index of the first element in the range
+ /// The number of elements in the range
+ ///
+ /// Offset or count is less than 0
+ ///
+ ///
+ /// Offset and count do not specify a valid range in array
+ ///
+ /// String is null
+ public StringSegment(string text, int offset, int count) {
+ if(text == null) {
+ throw new ArgumentNullException("array");
+ }
+ if(offset < 0) {
+ throw new ArgumentOutOfRangeException(
+ "offset", "Argument out of range, non-negative number required"
+ );
+ }
+ if(count < 0) {
+ throw new ArgumentOutOfRangeException(
+ "count", "Argument out of range, non-negative number required"
+ );
+ }
+ if((text.Length - offset) < count) {
+ throw new ArgumentException(
+ "Invalid argument, specified offset and count exceed string length"
+ );
+ }
+
+ this.text = text;
+ this.offset = offset;
+ this.count = count;
+ }
+
+ ///
+ /// Gets the original string containing the range of elements that the string
+ /// segment delimits
+ ///
+ ///
+ /// The original array that was passed to the constructor, and that contains the range
+ /// delimited by the
+ ///
+ public string Text {
+ get { return this.text; }
+ }
+
+ ///
+ /// Gets the position of the first element in the range delimited by the array segment,
+ /// relative to the start of the original array
+ ///
+ /// The position of the first element in the range delimited by the
+ /// , relative to the start of the original array
+ ///
+ public int Offset {
+ get { return this.offset; }
+ }
+
+ ///
+ /// Gets the number of elements in the range delimited by the array segment
+ ///
+ ///
+ /// The number of elements in the range delimited by the
+ ///
+ public int Count {
+ get { return this.count; }
+ }
+
+ /// Returns the hash code for the current instance
+ /// A 32-bit signed integer hash code
+ public override int GetHashCode() {
+ return ((this.text.GetHashCode() ^ this.offset) ^ this.count);
+ }
+
+ ///
+ /// Determines whether the specified object is equal to the current instance
+ ///
+ ///
+ /// True if the specified object is a structure and is
+ /// equal to the current instance; otherwise, false
+ ///
+ /// The object to be compared with the current instance
+ public override bool Equals(object other) {
+ return ((other is StringSegment) && this.Equals((StringSegment)other));
+ }
+
+ ///
+ /// Determines whether the specified structure is equal
+ /// to the current instance
+ ///
+ ///
+ /// True if the specified structure is equal to the
+ /// current instance; otherwise, false
+ ///
+ ///
+ /// The structure to be compared with the current instance
+ ///
+ public bool Equals(StringSegment other) {
+ return
+ (other.text == this.text) &&
+ (other.offset == this.offset) &&
+ (other.count == this.count);
+ }
+
+ ///
+ /// Indicates whether two structures are equal
+ ///
+ /// True if a is equal to b; otherwise, false
+ ///
+ /// The structure on the left side of the
+ /// equality operator
+ ///
+ ///
+ /// The structure on the right side of the
+ /// equality operator
+ ///
+ public static bool operator ==(StringSegment left, StringSegment right) {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Indicates whether two structures are unequal
+ ///
+ /// True if a is not equal to b; otherwise, false
+ ///
+ /// The structure on the left side of the
+ /// inequality operator
+ ///
+ ///
+ /// The structure on the right side of the
+ /// inequality operator
+ ///
+ public static bool operator !=(StringSegment left, StringSegment right) {
+ return !(left == right);
+ }
+
+ /// String wrapped by the string segment
+ private string text;
+ /// Offset in the original string the segment begins at
+ private int offset;
+ /// Number of characters in the segment
+ private int count;
+
+ }
+
+} // namespace Nuclex.Support