//******************************************************************************************************// StringParser.cs - Gbtc//// Copyright © 2017, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 07/01/2017 - F. Russell Robertson// Generated original version of source code.////****************************************************************************************************** using System;using System.Diagnostics.CodeAnalysis;using System.Linq; namespace GSF.Parsing{ /// <summary> /// Like the Excel CSV Parser, only better. /// </summary> public static class StringParser { private const char DoubleQuote = '\"'; private const char Comma = ','; private const int WorkingArraySize = 128; /// <summary> /// Returns the string that is between two delimiter strings beginning the first startDelimiter found. /// ALSO, returns the index of the payload (the index of the first char past the startDelimiter) /// </summary> /// <param name="inString">The input string</param> /// <param name="startToken">The beginning token or delimiter</param> /// <param name="endToken">The ending token or delimiter</param> /// <param name="startIndex">The index on which to begin searching inString</param> /// <param name="matchCase">set to FALSE for case insensitive test for delimiters</param> /// <param name="includeTokensInReturn">set to TRUE for the return string to include the opening and closing tokens.</param> /// <param name="payloadIndex"></param> /// <returns>A string, and the string starting index (payload Index)</returns> public static string GetBetweenDelimiters(string inString, out int payloadIndex, char startToken = ',', char endToken = ',', int startIndex = 0, bool matchCase = true, bool includeTokensInReturn = false) { payloadIndex = -1; if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; string testString = inString; if (!matchCase) { testString = inString.ToUpper(); startToken = startToken.ToUpper(); endToken = endToken.ToUpper(); } int iStart = testString.IndexOf(startToken, startIndex); if (iStart > -1) { iStart++; int iEnd = testString.IndexOf(endToken, iStart); if (iEnd > -1) { //Are there other open tokens in this range int[] opentags = IndicesOfToken(testString.Substring(iStart, iEnd - iStart), startToken); //If so, reach to the matching closing Token if (opentags != null && opentags.Length > 0) { for (int i = 0; i < opentags.Length; i++) { iEnd++; iEnd = testString.IndexOf(endToken, iEnd); if (iEnd < 0) break; } if (iEnd < 0) return null; } if (includeTokensInReturn) { payloadIndex = iStart - 1; return inString.Substring(payloadIndex, iEnd - iStart + 2); } payloadIndex = iStart; return inString.Substring(payloadIndex, iEnd - iStart); } return null; } return null; } /// <summary> /// Returns an array indices where the token char was found. Null for no tokens found. /// </summary> /// <param name="inString">The string to process</param> /// <param name="token">The token string sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns></returns> public static int[] IndicesOfToken(string inString, char token, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; int[] indices = new int[WorkingArraySize]; if (token == 0) return null; int count = 0; int k = IndexOfNextToken(inString, token, startIndex, 1, matchCase); while (k > -1) { indices[count++] = k; k = IndexOfNextToken(inString, token, k + 1, 1, matchCase); if (count >= indices.Length) Array.Resize(ref indices, indices.Length + WorkingArraySize); } if (count == 0) { Array.Resize(ref indices, 1); return null; } Array.Resize(ref indices, count); return indices; } /// <summary> /// Returns an array of indices where the token string was found /// </summary> /// <param name="inString">The string to process</param> /// <param name="token">The token string sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>null for no tokens found</returns> public static int[] IndicesOfToken(string inString, string token, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; int[] indices = new int[WorkingArraySize]; if (string.IsNullOrEmpty(token)) return null; int count = 0; int k = IndexOfNextToken(inString, token, startIndex, 1, matchCase); while (k > -1) { indices[count++] = k; k = IndexOfNextToken(inString, token, k + token.Length, 1, matchCase); if (count >= indices.Length) Array.Resize(ref indices, indices.Length + WorkingArraySize); } if (count <= 0) return null; Array.Resize(ref indices, count); return indices; } /// <summary> /// Returns an array of the indices where the token chars were found. Null for no tokens found. /// </summary> /// <param name="inString">The string to process</param> /// <param name="tokens">The char array of the tokens</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns></returns> public static int[] IndicesOfTokens(string inString, char[] tokens, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; int[] indices = new int[WorkingArraySize]; if (tokens == null || tokens[0] == 0) return null; int count = 0; int k = IndexOfNextTokens(inString, tokens, startIndex, matchCase); while (k > -1) { indices[count++] = k; k = IndexOfNextTokens(inString, tokens, k + 1, matchCase); if (count >= indices.Length) Array.Resize(ref indices, indices.Length + WorkingArraySize); } if (count == 0) { Array.Resize(ref indices, 1); return null; } Array.Resize(ref indices, count); return indices; } /// <summary> /// Finds the index of the "n" occurrence of a character (a token) within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The token character sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="occurrenceCount">The occurrence sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a character. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfNextToken(string inString, char token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (token == 0) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOf(token, startIndex); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOf(token, indexPos + 1); count++; } return indexPos; } /// <summary> /// Finds the index of the "n" occurrence of one string (a token) within another /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The string to find</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="occurrenceCount">The occurrence of the token sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a string. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfNextToken(string inString, string token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (string.IsNullOrEmpty(token)) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOf(token, startIndex, StringComparison.Ordinal); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOf(token, indexPos + 1, StringComparison.Ordinal); count++; } return indexPos; } /// <summary> /// Finds the index of the "n" occurrence any one of the chars in the token array within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="tokens">The token characters sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a character. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfNextTokens(string inString, char[] tokens, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (tokens == null) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (inString.IndexOfAny(tokens, startIndex) < 0) return -1; int i = 0; if (!matchCase) { inString = inString.ToUpper(); foreach (char c in tokens) { tokens[i++] = c.ToUpper(); } } int[] positions = new int[tokens.Length]; i = 0; foreach (char c in tokens) { positions[i] = inString.IndexOf(c, startIndex); if (positions[i] < 0) positions[i] = 32000; i++; } return positions.Min(); } /// <summary> /// Processing from RIGHT to LEFT, finds the index of the "n" occurrence of a character (a token) within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The token character sought</param> /// <param name="startIndex">Default of zero (0) begins testing end of inString, otherwise /// The index from with to begin processing inString from RIGHT to LEFT</param> /// <param name="occurrenceCount">The occurrence sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a character. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfPreviousToken(string inString, char token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (token == 0) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (startIndex == 0) startIndex = inString.Length - 1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOfPrevious(token, startIndex); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOfPrevious(token, indexPos - 1); count++; } return indexPos; } /// <summary> /// Processing from RIGHT to LEFT, finds the index of the "n"occurrence of one string (a token) within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The token string sought</param> /// <param name="startIndex">Default of zero (0) begins testing end of inString, otherwise /// The index from with to begin processing inString from RIGHT to LEFT</param> /// <param name="occurrenceCount">The occurrence sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a string. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfPreviousToken(string inString, string token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (string.IsNullOrEmpty(token)) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (startIndex == 0) startIndex = inString.Length - 1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOfPrevious(token, startIndex); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOfPrevious(token, indexPos - 1); count++; } return indexPos; } /// <summary> /// Looks to the RIGHT for the first open token and returns the matching close token /// </summary> /// <param name="inString">The string to process</param> /// <param name="openToken"></param> /// <param name="closeToken"></param> /// <param name="startIndex">The index from with to begin processing inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns></returns> public static int IndexOfMatchingCloseToken(string inString, string openToken, string closeToken, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (string.IsNullOrEmpty(openToken)) return -1; if (string.IsNullOrEmpty(closeToken)) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (!matchCase) { inString = inString.ToLower(); openToken = openToken.ToLower(); closeToken = closeToken.ToLower(); } int openTokenIndex = inString.IndexOf(openToken, startIndex, StringComparison.Ordinal); if (openTokenIndex < 0) return -1;Lines 1–500 of 1112. Load more
//****************************************************************************************************** // StringParser.cs - Gbtc // // Copyright © 2017, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 07/01/2017 - F. Russell Robertson // Generated original version of source code. // //****************************************************************************************************** using System; using System.Diagnostics.CodeAnalysis; using System.Linq; namespace GSF.Parsing { /// <summary> /// Like the Excel CSV Parser, only better. /// </summary> public static class StringParser { private const char DoubleQuote = '\"'; private const char Comma = ','; private const int WorkingArraySize = 128; /// <summary> /// Returns the string that is between two delimiter strings beginning the first startDelimiter found. /// ALSO, returns the index of the payload (the index of the first char past the startDelimiter) /// </summary> /// <param name="inString">The input string</param> /// <param name="startToken">The beginning token or delimiter</param> /// <param name="endToken">The ending token or delimiter</param> /// <param name="startIndex">The index on which to begin searching inString</param> /// <param name="matchCase">set to FALSE for case insensitive test for delimiters</param> /// <param name="includeTokensInReturn">set to TRUE for the return string to include the opening and closing tokens.</param> /// <param name="payloadIndex"></param> /// <returns>A string, and the string starting index (payload Index)</returns> public static string GetBetweenDelimiters(string inString, out int payloadIndex, char startToken = ',', char endToken = ',', int startIndex = 0, bool matchCase = true, bool includeTokensInReturn = false) { payloadIndex = -1; if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; string testString = inString; if (!matchCase) { testString = inString.ToUpper(); startToken = startToken.ToUpper(); endToken = endToken.ToUpper(); } int iStart = testString.IndexOf(startToken, startIndex); if (iStart > -1) { iStart++; int iEnd = testString.IndexOf(endToken, iStart); if (iEnd > -1) { //Are there other open tokens in this range int[] opentags = IndicesOfToken(testString.Substring(iStart, iEnd - iStart), startToken); //If so, reach to the matching closing Token if (opentags != null && opentags.Length > 0) { for (int i = 0; i < opentags.Length; i++) { iEnd++; iEnd = testString.IndexOf(endToken, iEnd); if (iEnd < 0) break; } if (iEnd < 0) return null; } if (includeTokensInReturn) { payloadIndex = iStart - 1; return inString.Substring(payloadIndex, iEnd - iStart + 2); } payloadIndex = iStart; return inString.Substring(payloadIndex, iEnd - iStart); } return null; } return null; } /// <summary> /// Returns an array indices where the token char was found. Null for no tokens found. /// </summary> /// <param name="inString">The string to process</param> /// <param name="token">The token string sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns></returns> public static int[] IndicesOfToken(string inString, char token, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; int[] indices = new int[WorkingArraySize]; if (token == 0) return null; int count = 0; int k = IndexOfNextToken(inString, token, startIndex, 1, matchCase); while (k > -1) { indices[count++] = k; k = IndexOfNextToken(inString, token, k + 1, 1, matchCase); if (count >= indices.Length) Array.Resize(ref indices, indices.Length + WorkingArraySize); } if (count == 0) { Array.Resize(ref indices, 1); return null; } Array.Resize(ref indices, count); return indices; } /// <summary> /// Returns an array of indices where the token string was found /// </summary> /// <param name="inString">The string to process</param> /// <param name="token">The token string sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>null for no tokens found</returns> public static int[] IndicesOfToken(string inString, string token, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; int[] indices = new int[WorkingArraySize]; if (string.IsNullOrEmpty(token)) return null; int count = 0; int k = IndexOfNextToken(inString, token, startIndex, 1, matchCase); while (k > -1) { indices[count++] = k; k = IndexOfNextToken(inString, token, k + token.Length, 1, matchCase); if (count >= indices.Length) Array.Resize(ref indices, indices.Length + WorkingArraySize); } if (count <= 0) return null; Array.Resize(ref indices, count); return indices; } /// <summary> /// Returns an array of the indices where the token chars were found. Null for no tokens found. /// </summary> /// <param name="inString">The string to process</param> /// <param name="tokens">The char array of the tokens</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns></returns> public static int[] IndicesOfTokens(string inString, char[] tokens, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return null; if (startIndex > inString.Length - 1 || startIndex < 0) return null; int[] indices = new int[WorkingArraySize]; if (tokens == null || tokens[0] == 0) return null; int count = 0; int k = IndexOfNextTokens(inString, tokens, startIndex, matchCase); while (k > -1) { indices[count++] = k; k = IndexOfNextTokens(inString, tokens, k + 1, matchCase); if (count >= indices.Length) Array.Resize(ref indices, indices.Length + WorkingArraySize); } if (count == 0) { Array.Resize(ref indices, 1); return null; } Array.Resize(ref indices, count); return indices; } /// <summary> /// Finds the index of the "n" occurrence of a character (a token) within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The token character sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="occurrenceCount">The occurrence sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a character. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfNextToken(string inString, char token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (token == 0) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOf(token, startIndex); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOf(token, indexPos + 1); count++; } return indexPos; } /// <summary> /// Finds the index of the "n" occurrence of one string (a token) within another /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The string to find</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="occurrenceCount">The occurrence of the token sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a string. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfNextToken(string inString, string token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (string.IsNullOrEmpty(token)) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOf(token, startIndex, StringComparison.Ordinal); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOf(token, indexPos + 1, StringComparison.Ordinal); count++; } return indexPos; } /// <summary> /// Finds the index of the "n" occurrence any one of the chars in the token array within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="tokens">The token characters sought</param> /// <param name="startIndex">The index from which to begin searching inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a character. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfNextTokens(string inString, char[] tokens, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (tokens == null) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (inString.IndexOfAny(tokens, startIndex) < 0) return -1; int i = 0; if (!matchCase) { inString = inString.ToUpper(); foreach (char c in tokens) { tokens[i++] = c.ToUpper(); } } int[] positions = new int[tokens.Length]; i = 0; foreach (char c in tokens) { positions[i] = inString.IndexOf(c, startIndex); if (positions[i] < 0) positions[i] = 32000; i++; } return positions.Min(); } /// <summary> /// Processing from RIGHT to LEFT, finds the index of the "n" occurrence of a character (a token) within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The token character sought</param> /// <param name="startIndex">Default of zero (0) begins testing end of inString, otherwise /// The index from with to begin processing inString from RIGHT to LEFT</param> /// <param name="occurrenceCount">The occurrence sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a character. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfPreviousToken(string inString, char token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (token == 0) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (startIndex == 0) startIndex = inString.Length - 1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOfPrevious(token, startIndex); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOfPrevious(token, indexPos - 1); count++; } return indexPos; } /// <summary> /// Processing from RIGHT to LEFT, finds the index of the "n"occurrence of one string (a token) within a string /// </summary> /// <param name="inString">The string to process.</param> /// <param name="token">The token string sought</param> /// <param name="startIndex">Default of zero (0) begins testing end of inString, otherwise /// The index from with to begin processing inString from RIGHT to LEFT</param> /// <param name="occurrenceCount">The occurrence sought</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns>Returns the starting index of the nth occurrence of a string. /// Returns -1 if nth occurrence does not exist.</returns> public static int IndexOfPreviousToken(string inString, string token, int startIndex = 0, int occurrenceCount = 1, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (string.IsNullOrEmpty(token)) return -1; if (occurrenceCount < 1) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (startIndex == 0) startIndex = inString.Length - 1; if (!matchCase) { inString = inString.ToUpper(); token = token.ToUpper(); } int count = 1; int indexPos = inString.IndexOfPrevious(token, startIndex); while (indexPos > -1 && count != occurrenceCount) { indexPos = inString.IndexOfPrevious(token, indexPos - 1); count++; } return indexPos; } /// <summary> /// Looks to the RIGHT for the first open token and returns the matching close token /// </summary> /// <param name="inString">The string to process</param> /// <param name="openToken"></param> /// <param name="closeToken"></param> /// <param name="startIndex">The index from with to begin processing inString</param> /// <param name="matchCase">Set to FALSE for case insensitive search</param> /// <returns></returns> public static int IndexOfMatchingCloseToken(string inString, string openToken, string closeToken, int startIndex = 0, bool matchCase = true) { if (string.IsNullOrEmpty(inString)) return -1; if (string.IsNullOrEmpty(openToken)) return -1; if (string.IsNullOrEmpty(closeToken)) return -1; if (startIndex > inString.Length - 1 || startIndex < 0) return -1; if (!matchCase) { inString = inString.ToLower(); openToken = openToken.ToLower(); closeToken = closeToken.ToLower(); } int openTokenIndex = inString.IndexOf(openToken, startIndex, StringComparison.Ordinal); if (openTokenIndex < 0) return -1;