I have some string like this:
str1 = STA001, str2 = STA002, str3 = STA003
and have code to compare strings:
private bool IsSubstring(string strChild, string strParent)
{
if (!strParent.Contains(strChild))
{
return false;
}
else return true;
}
If I have strChild = STA001STA002 and strParent = STA001STA002STA003 then return true but when I enter strChild = STA001STA003 and check with strParent = STA001STA002STA003 then return false although STA001STA003 have contains in strParent. How can i resolve it?
What you're describing is not a substring. It is basically asking of two collections the question "is this one a subset of the other one?" This question is far easier to ask when the collection is a set such as HashSet<T> than when the collection is a big concatenated string.
This would be a much better way to write your code:
var setOne = new HashSet<string> { "STA001", "STA003" };
var setTwo = new HashSet<string> { "STA001", "STA002", "STA003" };
Console.WriteLine(setOne.IsSubsetOf(setTwo)); // True
Console.WriteLine(setTwo.IsSubsetOf(setOne)); // False
Or, if the STA00 part was just filler to make it make sense in the context of strings, then use ints directly:
var setOne = new HashSet<int> { 1, 3 };
var setTwo = new HashSet<int> { 1, 2, 3 };
Console.WriteLine(setOne.IsSubsetOf(setTwo)); // True
Console.WriteLine(setTwo.IsSubsetOf(setOne)); // False
The Contains method only looks for an exact match, it doesn't look for parts of the string.
Divide the child string into its parts, and look for each part in the parent string:
private bool IsSubstring(string child, string parent) {
for (int i = 0; i < child.Length; i+= 6) {
if (!parent.Contains(child.Substring(i, 6))) {
return false;
}
}
return true;
}
You should however consider it cross-part matches are possible, and if that is an issue. E.g. looking for "1STA00" in "STA001STA002". If that would be a problem, then you should divide the parent string similarly, and only make direct comparisons between the parts, not using the Contains method.
Note: Using hungarian notation for the data type of variables is not encouraged in C#.
This may be a bit on the overkill side, but it might be incredibly beneficial.
private static bool ContainedWord(string input, string phrase)
{
var pattern = String.Format(#"\b({0})", phrase);
var result = Regex.Match(input, pattern);
if(string.Compare(result, phrase) == 0)
return true;
return false;
}
If the expression finds a match, then compare the result to your phrase. If they're zero, it matched. I may be misunderstanding your intent.
Related
Firstly I understand that there are several ways to do this and I do have some code which runs, but what I just wanted to find out was if anyone else has a recommended way to do this. Say I have a string which I already know that would have contain a specific character (a ‘,’ in this case). Now I just want to validate that this comma is used only once and not more. I know iterating through each character is an option but why go through all that work because I just want to make sure that this special character is not used more than once, I’m not exactly interested in the count per se. The best I could think was to use the split and here is some sample code that works. Just curious to find out if there is a better way to do this.
In summary,
I have a certain string in which I know has a special character (‘,’ in this case)
I want to validate that this special character has only been used once in this string
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Split(characterToBeEvaluated).Length - 1;
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
You can use string's IndexOf methods:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
string substringToFind = characterToBeEvaluated.ToString();
int firstIdx = myStringToBeTested.IndexOf(substringToFind, StringComparison.Ordinal);
bool foundOnce = firstIdx >= 0;
bool foundTwice = foundOnce && myStringToBeTested.IndexOf(substringToFind, firstIdx + 1, StringComparison.Ordinal) >= 0;
Try it online
You could use the LINQ Count() method:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Count(x => x == characterToBeEvaluated);
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
This is the most readable and simplest approach and is great if you need to know the exact count but for your specific case #ProgrammingLlama's answer is better in terms of efficiency.
Adding another answer using a custom method:
public static void Main()
{
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var characterAppearsOnlyOnce = DoesCharacterAppearOnlyOnce(characterToBeEvaluated, myStringToBeTested);
if (characterAppearsOnlyOnce)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
}
public static bool DoesCharacterAppearOnlyOnce(char characterToBeEvaluated, string stringToBeTested)
{
int count = 0;
for (int i = 0; i < stringToBeTested.Length && count < 2; ++i)
{
if (stringToBeTested[i] == characterToBeEvaluated)
{
++count;
}
}
return count == 1;
}
The custom method DoesCharacterAppearOnlyOnce() performs better than the method using IndexOf() for smaller strings - probably due to the overhead calling IndexOf. As the strings get larger the IndexOf method is better.
I have a text file full of strings, one on each line. Some of these strings will contain an unknown number of "#" characters. Each "#" can represent the numbers 1, 2, 3, or 4. I want to generate all possible combinations (permutations?) of strings for each of those "#"s. If there were a set number of "#"s per string, I'd just use nested for loops (quick and dirty). I need help finding a more elegant way to do it with an unknown number of "#"s.
Example 1: Input string is a#bc
Output strings would be:
a1bc
a2bc
a3bc
a4bc
Example 2: Input string is a#bc#d
Output strings would be:
a1bc1d
a1bc2d
a1bc3d
a1bc4d
a2bc1d
a2bc2d
a2bc3d
...
a4bc3d
a4bc4d
Can anyone help with this one? I'm using C#.
This is actually a fairly good place for a recursive function. I don't write C#, but I would create a function List<String> expand(String str) which accepts a string and returns an array containing the expanded strings.
expand can then search the string to find the first # and create a list containing the first part of the string + expansion. Then, it can call expand on the last part of the string and add each element in it's expansion to each element in the last part's expansion.
Example implementation using Java ArrayLists:
ArrayList<String> expand(String str) {
/* Find the first "#" */
int i = str.indexOf("#");
ArrayList<String> expansion = new ArrayList<String>(4);
/* If the string doesn't have any "#" */
if(i < 0) {
expansion.add(str);
return expansion;
}
/* New list to hold the result */
ArrayList<String> result = new ArrayList<String>();
/* Expand the "#" */
for(int j = 1; j <= 4; j++)
expansion.add(str.substring(0,i-1) + j);
/* Combine every expansion with every suffix expansion */
for(String a : expand(str.substring(i+1)))
for(String b : expansion)
result.add(b + a);
return result;
}
I offer you here a minimalist approach for the problem at hand.
Yes, like other have said recursion is the way to go here.
Recursion is a perfect fit here, since we can solve this problem by providing the solution for a short part of the input and start over again with the other part until we are done and merge the results.
Every recursion must have a stop condition - meaning no more recursion needed.
Here my stop condition is that there are no more "#" in the string.
I'm using string as my set of values (1234) since it is an IEnumerable<char>.
All other solutions here are great, Just wanted to show you a short approach.
internal static IEnumerable<string> GetStrings(string input)
{
var values = "1234";
var permutations = new List<string>();
var index = input.IndexOf('#');
if (index == -1) return new []{ input };
for (int i = 0; i < values.Length; i++)
{
var newInput = input.Substring(0, index) + values[i] + input.Substring(index + 1);
permutations.AddRange(GetStrings(newInput));
}
return permutations;
}
An even shorter and cleaner approach with LINQ:
internal static IEnumerable<string> GetStrings(string input)
{
var values = "1234";
var index = input.IndexOf('#');
if (index == -1) return new []{ input };
return
values
.Select(ReplaceFirstWildCardWithValue)
.SelectMany(GetStrings);
string ReplaceFirstWildCardWithValue(char value) => input.Substring(0, index) + value + input.Substring(index + 1);
}
This is shouting out loud for a recursive solution.
First, lets make a method that generates all combinations of a certain length from a given set of values. Because we are only interested in generating strings, lets take advantage of the fact that string is immutable (see P.D.2); this makes recursive functions so much easier to implement and reason about:
static IEnumerable<string> GetAllCombinations<T>(
ISet<T> set, int length)
{
IEnumerable<string> getCombinations(string current)
{
if (current.Length == length)
{
yield return current;
}
else
{
foreach (var s in set)
{
foreach (var c in getCombinations(current + s))
{
yield return c;
}
}
}
}
return getCombinations(string.Empty);
}
Study carefully how this methods works. Work it out by hand for small examples to understand it.
Now, once we know how to generate all possible combinations, building the strings is easy:
Figure out the number of wildcards in the specified string: this will be our combination length.
For every combination, insert in order each character into the string where we encounter a wildcard.
Ok, lets do just that:
public static IEnumerable<string> GenerateCombinations<T>(
this string s,
IEnumerable<T> set,
char wildcard)
{
var length = s.Count(c => c == wildcard);
var combinations = GetAllCombinations(set, length);
var builder = new StringBuilder();
foreach (var combination in combinations)
{
var index = 0;
foreach (var c in s)
{
if (c == wildcard)
{
builder.Append(combination[index]);
index += 1;
}
else
{
builder.Append(c);
}
}
yield return builder.ToString();
builder.Clear();
}
}
And we're done. Usage would be:
var set = new HashSet<int>(new[] { 1, 2, 3, 4 });
Console.WriteLine(
string.Join("; ", "a#bc#d".GenerateCombinations(set, '#')));
And sure enough, the output is:
a1bc1d; a1bc2d; a1bc3d; a1bc4d; a2bc1d; a2bc2d; a2bc3d;
a2bc4d; a3bc1d; a3bc2d; a3bc3d; a3bc4d; a4bc1d; a4bc2d;
a4bc3d; a4bc4d
Is this the most performant or efficient implementation? Probably not but its readable and maintainable. Unless you have a specific performance goal you are not meeting, write code that works and is easy to understand.
P.D. I’ve omitted all error handling and argument validation.
P.D.2: if the length of the combinations is big, concatenting strings inside GetAllCombinations might not be a good idea. In that case I’d have GetAllCombinations return an IEnumerable<IEnumerable<T>>, implement a trivial ImmutableStack<T>, and use that as the combination buffer instead of string.
I am fairly new to coding so I guess I´m not seeing the obvious answer by myself so I am sorry if this is a silly question but I´m really stucked here. I am trying to compare two sets of trigrams from two different texts (A and B). If there are no trigrams in B present on A, then I would say those two texts are different, at least for my present purpose. I am using Nuve for trigram extraction.
So far I have this:
var paragraph = "This is not a phrase. This is not a sentence.";
var paragraph2 = "This is a phrase. This is a sentence. This have nothing to do with sentences.";
ITokenizer tokenizer = new ClassicTokenizer(true);
SentenceSegmenter segmenter = new TokenBasedSentenceSegmenter(tokenizer);
var sentences = segmenter.GetSentences(paragraph);
ITokenizer tokenizer2 = new ClassicTokenizer(true);
SentenceSegmenter segmenter2 = new TokenBasedSentenceSegmenter(tokenizer2);
var sentences2 = segmenter2.GetSentences(paragraph2);
var extractor = new NGramExtractor(3);
var grams1 = extractor.ExtractAsList(sentences);
var grams2 = extractor.ExtractAsList(sentences2);
var nonintersect = grams2.Except(grams1);
foreach (var nGram in nonintersect)
{
var current = nGram;
bool found = false;
foreach (var n in grams2)
{
if (!found)
{
if (n == current)
{
found = true;
}
}
}
if (!found)
{
var result = current;
string finalresult = Convert.ToString(result);
textBox3.AppendText(finalresult+ "\n");
}
This way I hope to get the sentences that, being in B, are not present in A (i.e. all the sentences from B in the example), but now I would have to compare each trigram from B to each trigram from A to see if sentences are really different from each other. I have tried to do so with another nested foreach but I get just nonsense data, as follows:
foreach (var sentence2 in sentences2)
{
var actual = sentence2;
bool found1 = false;
foreach (var sentence in sentences)
{
if (!found1)
{
if (actual == sentence)
{
found1 = true;
}
}
}
if (!found1)
{
string finalresult= Convert.ToString(actual);
textBox3.AppendText(finalresult+ "\n");
}
}
Doing this I try to verify if the trigrams from each sentence in B are equal to the trigrams from each sentence in A and, if they are, then textBox3 would be empty.
Briefly, I am trying to code something similar to Ferret but for C# and only for comparing two given plain texts. As far as I know, there is nothing similar already done for C#.
Any help or tip would be really appreciated. Thanks!
Comparing bodies of text
Comparing two bodies of text and marking them as similar if they have at least one sentence-level trigram in common is fairly straight-forward:
public bool AreTextsSimilar(string a, string b)
{
// We can reuse these objects - they could be stored in member fields:
ITokenizer tokenizer = new ClassicTokenizer(true);
SentenceSegmenter segmenter = new TokenBasedSentenceSegmenter(tokenizer);
NGramExtractor trigramExtractor = new NGramExtractor(3);
IEnumerable<string> sentencesA = segmenter.GetSentences(a);
IEnumerable<string> sentencesB = segmenter.GetSentences(b);
// The order of trigrams doesn't matter, so we'll fetch them as sets instead,
// to make comparisons between their elements more efficient:
ISet<NGram> trigramsA = trigramExtractor.ExtractAsSet(sentencesA);
ISet<NGram> trigramsB = trigramExtractor.ExtractAsSet(sentencesB);
// 'Intersect' returns all elements that are found in both collections:
IEnumerable<NGram> sharedTrigrams = trigramsA.Intersect(trigramsB);
// 'Any' only returns true if the collection isn't empty:
return sharedTrigrams.Any();
}
Without Linq methods (Intersect, Any), those last two lines could be implemented as a loop:
foreach (NGram trigramA in trigramsA)
{
// As soon as we find a shared sentence trigram we can conclude that
// the two bodies of text are indeed similar:
if (trigramsB.Contains(trigramA))
return true;
}
return false;
}
Sentences without shared word trigrams
Retrieving all sentences that do not share word-level trigrams takes some more work:
public IEnumerable<string> GetUniqueBSentences(string a, string b)
{
// We can reuse these objects - they could be stored in member fields:
ITokenizer tokenizer = new ClassicTokenizer(true);
SentenceSegmenter segmenter = new TokenBasedSentenceSegmenter(tokenizer);
NGramExtractor trigramExtractor = new NGramExtractor(3);
IEnumerable<string> sentencesA = segmenter.GetSentences(a);
IEnumerable<string> sentencesB = segmenter.GetSentences(b);
ITokenizer wordTokenizer = new ClassicTokenizer(false);
foreach (string sentenceB in sentencesB)
{
IList<string> wordsB = wordTokenizer.Tokenize(sentenceB);
ISet<NGram> wordTrigramsB = trigramExtractor.ExtractAsSet(wordsB);
bool foundMatchingSentence = false;
foreach (string sentenceA in sentencesA)
{
// This will be repeated for every sentence in B. It would be more efficient
// to generate trigrams for all sentences in A once, before we enter these loops:
IList<string> wordsA = wordTokenizer.Tokenize(sentenceA);
ISet<NGram> wordTrigramsA = trigramExtractor.ExtractAsSet(wordsA);
if (wordTrigramsA.Intersect(wordTrigramsB).Any())
{
// We found a sentence in A that shares word-trigrams, so stop comparing:
foundMatchingSentence = true;
break;
}
}
// No matching sentence in A? Then this sentence is unique to B:
if (!foundMatchingSentence)
yield return sentenceB;
}
}
Apparently segmenter also returns an extra, empty sentence, which you may want to filter out (or figure out how to prevent segmenter from doing that).
I'm sure the above code can be optimized if performance is a concern, but I'll leave that up to you.
I am trying to extract the number out of the last part of the string, I have wrote a function to do this but am having problems with out of range index.
Here is the string
type="value" cat=".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.1" descCat=".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.3"
and here is my function
private static string ExtractDescOID(string property)
{
string result = "";
int startPos = property.LastIndexOf("descOid=\"") + "descOid=\"".Length;
int endPos = property.Length - 1;
if (endPos - startPos != 1)
{
//This now gets rid of the first . within the string.
startPos++;
result = property.Substring(startPos, endPos);
}
else
{
result = "";
}
if (startPos == endPos)
{
Console.WriteLine("Something has gone wrong");
}
return result;
}
I want to be able to get 1.3.6.1.4.1.26928.1.1.1.2.1.2.1.3 this part of the string. I have stepped through the code, the string length is 99 however when AND MY startPos becomes 64 and endPos becomes 98 which is actually within the range.
The second argument to Substring(int, int) isn't the "end position", but the length of the substring to return.
result = property.Substring(startPos, endPos - startPos);
Read the documentation again, the second value is the length, not the index.
As found on MSDN:
public string Substring(
int startIndex,
int length
)
A different approach to this problem could be through using string.Split() to take care of the parsing for you. The only reason why I would propose this (other than that I like to present additional options to what's already there, plus this is the lazy man's way out) is that from a code perspective, the code is easier IMHO to decompose, and when decomposed, is easier to comprehend by others.
Here's the sample program with some comments to illustrate my point (tested, btw).
class Program
{
static void Main(string[] args)
{
var someAttributesFromAnXmlNodeIGuess =
"type=\"value\" cat=\".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.1\" descCat=\".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.3\"";
var descCat = GetMeTheAttrib(someAttributesFromAnXmlNodeIGuess, "descCat");
Console.WriteLine(descCat);
Console.ReadLine();
}
// making the slightly huge assumption that you may want to
// access other attribs in the string...
private static string GetMeTheAttrib(string attribLine, string attribName)
{
var parsedDictionary = ParseAttributes(attribLine);
if (parsedDictionary.ContainsKey(attribName))
{
return parsedDictionary[attribName];
}
return string.Empty;
}
// keeping the contracts simple -
// i could have used IDictionary, which might make sense
// if this code became LINQ'd one day
private static Dictionary<string, string> ParseAttributes(string attribLine)
{
var dictionaryToReturn = new Dictionary<string, string>();
var listOfPairs = attribLine.Split(' '); // items look like type=value, etc
foreach (var pair in listOfPairs)
{
var attribList = pair.Split('=');
// we were expecting a type=value pattern... if this doesn't match then let's ignore it
if (attribList.Count() != 2) continue;
dictionaryToReturn.Add(attribList[0], attribList[1]);
}
return dictionaryToReturn;
}
}
Lets say I have several short string:
string[] shortStrings = new string[] {"xxx","yyy","zzz"};
(this definition can change length on array and on string too, so not a fixed one)
When a given string, I like to check if it combines with the shortStrings ONLY, how?
let say function is like bool TestStringFromShortStrings(string s)
then
TestStringFromShortStrings("xxxyyyzzz") = true;
TestStringFromShortStrings("xxxyyyxxx") = true;
TestStringFromShortStrings("xxxyyy") = true;
TestStringFromShortStrings("xxxxxx") = true;
TestStringFromShortStrings("xxxxx") = false;
TestStringFromShortStrings("xxxXyyyzzz") = false;
TestStringFromShortStrings("xxx2yyyxxx") = false;
Please suggest a memory not tense and relatively fast method.
[EIDT] What this function for?
I will personally use this function to test if a string is a combination of a PINYIN ok, some Chinese stuff. Following Chinese are same thing if you cannot read it.
检测一个字符串是否为汉语拼音(例如检测是否拼音域名)
所有的汉语拼音字符串有:
(To detect whether a string is Hanyu Pinyin (e.g. detect the phonetic domain) of the Pinyin string:)
Regex PinYin = new Regex(#"^(a|ai|an|ang|ao|ba|bai|ban|bang|bao|bei|ben|beng|bi|bian|biao|bie|bin|bing|bo|bu|ca|cai|can|cang|cao|ce|cen|ceng|cha|chai|chan|chang|chao|che|chen|cheng|chi|chong|chou|chu|chua|chuai|chuan|chuang|chui|chun|chuo|ci|cong|cou|cu|cuan|cui|cun|cuo|da|dai|dan|dang|dao|de|den|dei|deng|di|dia|dian|diao|die|ding|diu|dong|dou|du|duan|dui|dun|duo|e|ei|en|eng|er|fa|fan|fang|fei|fen|feng|fo|fou|fu|ga|gai|gan|gang|gao|ge|gei|gen|geng|gong|gou|gu|gua|guai|guan|guang|gui|gun|guo|ha|hai|han|hang|hao|he|hei|hen|heng|hong|hou|hu|hua|huai|huan|huang|hui|hun|huo|ji|jia|jian|jiang|jiao|jie|jin|jing|jiong|jiu|ju|juan|jue|jun|ka|kai|kan|kang|kao|ke|ken|keng|kong|kou|ku|kua|kuai|kuan|kuang|kui|kun|kuo|la|lai|lan|lang|lao|le|lei|leng|li|lia|lian|liang|liao|lie|lin|ling|liu|long|lou|lu|lv|luan|lue|lve|lun|luo|ma|mai|man|mang|mao|me|mei|men|meng|mi|mian|miao|mie|min|ming|miu|mo|mou|mu|na|nai|nan|nang|nao|ne|nei|nen|neng|ni|nian|niang|niao|nie|nin|ning|niu|nong|nou|nu|nv|nuan|nuo|nun|ou|pa|pai|pan|pang|pao|pei|pen|peng|pi|pian|piao|pie|pin|ping|po|pou|pu|qi|qia|qian|qiang|qiao|qie|qin|qing|qiong|qiu|qu|quan|que|qun|ran|rang|rao|re|ren|reng|ri|rong|rou|ru|ruan|rui|run|ruo|sa|sai|san|sang|sao|se|sen|seng|sha|shai|shan|shang|shao|she|shei|shen|sheng|shi|shou|shu|shua|shuai|shuan|shuang|shui|shun|shuo|si|song|sou|su|suan|sui|sun|suo|ta|tai|tan|tang|tao|te|teng|ti|tian|tiao|tie|ting|tong|tou|tu|tuan|tui|tun|tuo|wa|wai|wan|wang|wei|wen|weng|wo|wu|xi|xia|xian|xiang|xiao|xie|xin|xing|xiong|xiu|xu|xuan|xue|xun|ya|yan|yang|yao|ye|yi|yin|ying|yo|yong|you|yu|yuan|yue|yun|za|zai|zan|zang|zao|ze|zei|zen|zeng|zha|zhai|zhan|zhang|zhao|zhe|zhei|zhen|zheng|zhi|zhong|zhou|zhu|zhua|zhuai|zhuan|zhuang|zhui|zhun|zhuo|zi|zong|zou|zu|zuan|zui|zun|zuo)+$");
用下面的正则表达式方法,试过了,最简单而且效果非常好,就是有点慢:(
递归的方式对长字符串比较麻烦,容易内存溢出
(Tried it with the regular expression: it's the most simple and gives very good results, but it's a bit slow. The recursive way on the long string is too much trouble, it's too easy to overflow the stack.)
Edit: Simplified this a lot thanks to L.B and millimoose.
Regular Expressions to the rescue! Using System.Text.RegularExpressions.Regex, we get:
public static bool TestStringFromShortStrings(string checkText, string[] pieces) {
// Build the expression. Ultimate result will be
// of the form "^(xxx|yyy|zzz)+$".
var expr = "^(" +
String.Join("|", pieces.Select(Regex.Escape)) +
")+$";
// Check whether the supplied string matches the expression.
return Regex.IsMatch(checkText, expr);
}
This should be able to properly handle cases that have multiple repeated patterns of different lenghts. E.g. if you the list of possible pieces includes strings "xxx" and "xxxx".
Copy the target string to string builder. For each string in shortstring array, remove all occurences from target. If u end up in zero length string, true else false.
Edit:
This approach is not correct. Please refer to comments. Keeping this answer still here as it may look reasonably correct initially.
You could compare the start of the input string with each of the short strings. As soon as you have a match, you take the rest of the string and repeat. As soon as you have no more string left, you're done. For example:
string[] shortStrings = new string[] { "xxx", "yyy", "zzz" };
bool Test(string input)
{
if (input.Length == 0)
return true;
foreach (string shortStr in shortStrings)
{
if (input.StartsWith(shortStr))
{
if (Test(input.Substring(shortStr.Length)))
return true;
}
}
return false;
}
You might optimize this by removing the recursion, or by sorting the short strings and do a binary instead of a linear search.
Here is a non-recursive version, that uses a Stack object instead. No chance of getting a StackOverflowException:
string[] shortStrings = new string[] { "xxx", "yyy", "zzz" };
bool Test(string input)
{
Stack<string> stack = new Stack<string>();
stack.Push(input);
while (stack.Count > 0)
{
string str = stack.Pop();
if (str.Length == 0)
return true;
foreach (string shortStr in shortStrings)
{
if (str.StartsWith(shortStr))
stack.Push(str.Substring(shortStr.Length));
}
}
return false;
}