/* Function: GetParametersIndex * If a plain text string ends in parameters, returns the index of the opening brace character. Returns -1 otherwise. */ public static int GetParametersIndex(string input) { if (input == null) { return(-1); } input = input.TrimEnd(); int index = input.Length - 1; if (input.Length >= 2 && IsClosingBrace(input[index])) { // We have to count the braces so it correctly returns "(paren2)" from "text (paren) text2 (paren2)" and not // "(paren) text2 (paren2)". We also want to handle nested braces. Collections.SafeStack <char> braces = new Collections.SafeStack <char>(); braces.Push(input[index]); while (index > 0) { // The start position LastIndexOfAny() takes is the character at the end of the string to be examined first. // The count is the number of characters to examine, so it's one higher as index 4 goes for 5 characters: indexes 0, 1, 2, // 3, and 4. The character at the start position is examined, it's not a limit. index = input.LastIndexOfAny(AllBraces, index - 1, index); if (index == -1) { break; } if (IsClosingBrace(input[index])) { braces.Push(input[index]); } else // IsOpeningBrace(input[index]) { if (BracesMatch(input[index], braces.Peek())) { braces.Pop(); if (braces.Count == 0) { break; } } else { break; } } } // We don't want to count the angle brackets in "operator<string>" as parameters since this is the distinguishing part of // the name. if (index >= 0 && input[index] == '<') { int lookbehind = index - 1; while (lookbehind > 0 && input[lookbehind] == ' ') { lookbehind--; } if (lookbehind >= 7 && string.Compare(input, lookbehind - 7, "operator", 0, 8, true) == 0) { return(-1); } } // We want index to be greater than zero so we don't include cases where the entire title is surrounded // by braces. if (braces.Count == 0 && index > 0) { return(index); } } return(-1); }
/* Function: FromPlainText * Creates a ParameterString from plain text such as "(int, int)". You can extract them from a plain text identifier with * <GetParametersIndex()>. */ public static ParameterString FromPlainText(string input) { if (input == null) { throw new NullReferenceException(); } input = input.Trim(); #if DEBUG if ((input.Length < 2 || IsOpeningBrace(input[0]) == false || IsClosingBrace(input[input.Length - 1]) == false) && GetParametersIndex(input) != -1) { throw new Exception("Passed a full identifier to ParameterString.FromPlainText(). Separate the parameters from the identifier first."); } #endif if (input.Length < 2 || IsOpeningBrace(input[0]) == false || IsClosingBrace(input[input.Length - 1]) == false) { throw new FormatException(); } input = input.Substring(1, input.Length - 2); // Strip surrounding braces. input = input.Trim(); if (input == "") { return(new ParameterString()); } System.Text.StringBuilder output = new System.Text.StringBuilder(input.Length); // Ignore separators appearing within braces. We've already filtered out the surrounding braces and we shouldn't have to // worry about quotes because we should only have types, not default values. Collections.SafeStack <char> braces = new Collections.SafeStack <char>(); int startParam = 0; int index = input.IndexOfAny(AllBracesAndParamSeparators); while (index != -1) { char character = input[index]; if (IsOpeningBrace(character)) { braces.Push(character); } else if (BracesMatch(braces.Peek(), character)) { braces.Pop(); } else if ((character == ',' || character == ';') && braces.Count == 0) { NormalizeAndAppend(input.Substring(startParam, index - startParam), output); output.Append(SeparatorChar); startParam = index + 1; } index = input.IndexOfAny(AllBracesAndParamSeparators, index + 1); } NormalizeAndAppend(input.Substring(startParam), output); return(new ParameterString(output.ToString())); }