对于可能包含零个或多个连字符的字符串,我需要使用和不连字符提取所有不同的可能性。
例如,字符串" A-B"会导致" A-B"和" AB" (两种可能性)。
字符串" A-B-C"会导致" A-B-C"," AB-C"," A-BC"和" ABC" (四种可能性)。
字符串" A-B-C-D"将导致" ABC-D"," AB-C-D"," A-BC-D"," AB-CD" ," AB-CD"," ABC-D"," A-BCD"和" ABCD" (八种可能性)。
......等等。
我已尝试过一些嵌套循环,但无法获得所需的结果。我怀疑我需要一些递归的东西,除非有一些我忽略的简单解决方案。
NB。这是为了构建一个SQL查询(遗憾的是SQL Server没有MySQL的REGEXP模式匹配)。
这是我正在努力的一次尝试。如果我以递归方式执行此操作,这可能会有效。
string keyword = "A-B-C-D";
List<int> hyphens = new List<int>();
int pos = keyword.IndexOf('-');
while (pos != -1)
{
hyphens.Add(pos);
pos = keyword.IndexOf('-', pos + 1);
}
for (int i = 0; i < hyphens.Count(); i++)
{
string result = keyword.Substring(0, hyphens[i]) + keyword.Substring(hyphens[i] + 1);
Response.Write("<p>" + result);
}
A B C D是不同长度的词。
答案 0 :(得分:7)
查看您的示例案例。你注意到了一种模式吗?
可能性的数量是2 n 。
这实际上是指数式增长,因此如果字符串中有过多的连字符,那么将它们全部打印将很快变得不可行。 (只有30个连字符,有超过十亿种组合!)
也就是说,对于较少数量的连字符,生成列表可能会很有趣。为此,您可以将每个连字符视为二进制数中的一个位。如果该位为1,则连字符存在,否则不存在。所以这表明了一个相当简单的解决方案:
翻译成我们的代码:
public static IEnumerable<string> EnumerateHyphenatedStrings(string s)
{
string[] parts = s.Split('-');
int n = parts.Length - 1;
if (n > 30) throw new Exception("too many hyphens");
for (int m = (1 << n) - 1; m >= 0; m--)
{
StringBuilder sb = new StringBuilder(parts[0]);
for (int i = 1; i <= n; i++)
{
if ((m & (1 << (i - 1))) > 0) sb.Append('-');
sb.Append(parts[i]);
}
yield return sb.ToString();
}
}
答案 1 :(得分:5)
你应该能够跟踪每个连字符位置,并且基本上说它在那里或不在那里。循环遍历所有组合,你就得到了所有的字符串。我发现跟踪它的最简单方法是使用二进制文件,因为它很容易添加Convert.ToInt32
我想出了这个:
string keyword = "A-B-C-D";
string[] keywordSplit = keyword.Split('-');
int combinations = Convert.ToInt32(Math.Pow(2.0, keywordSplit.Length - 1.0));
List<string> results = new List<string>();
for (int j = 0; j < combinations; j++)
{
string result = "";
string hyphenAdded = Convert.ToString(j, 2).PadLeft(keywordSplit.Length - 1, '0');
// Generate string
for (int i = 0; i < keywordSplit.Length; i++)
{
result += keywordSplit[i] +
((i < keywordSplit.Length - 1) && (hyphenAdded[i].Equals('1')) ? "-" : "");
}
results.Add(result);
}
答案 2 :(得分:3)
这对我有用:
Func<IEnumerable<string>, IEnumerable<string>> expand = null;
expand = xs =>
{
if (xs != null && xs.Any())
{
var head = xs.First();
if (xs.Skip(1).Any())
{
return expand(xs.Skip(1)).SelectMany(tail => new []
{
head + tail,
head + "-" + tail
});
}
else
{
return new [] { head };
}
}
else
{
return Enumerable.Empty<string>();
}
};
var keyword = "A-B-C-D";
var parts = keyword.Split('-');
var results = expand(parts);
我明白了:
ABCD A-BCD AB-CD A-B-CD ABC-D A-BC-D AB-C-D A-B-C-D
答案 3 :(得分:1)
我不确定你的问题是否完全明确(即你能不能使用A-BCD-EF-G-H?)。对于&#34;完全&#34;连字符串(A-B-C-D -...- Z),这样的事情应该这样做:
string toParse = "A-B-C-D";
char[] toParseChars = toPase.toCharArray();
string result = "";
string binary;
for(int i = 0; i < (int)Math.pow(2, toParse.Length/2); i++) { // Number of subsets of an n-elt set is 2^n
binary = Convert.ToString(i, 2);
while (binary.Length < toParse.Length/2) {
binary = "0" + binary;
}
char[] binChars = binary.ToCharArray();
for (int k = 0; k < binChars.Length; k++) {
result += toParseChars[k*2].ToString();
if (binChars[k] == '1') {
result += "-";
}
}
result += toParseChars[toParseChars.Length-1];
Console.WriteLine(result);
}
这里的想法是我们想为每个可能的连字符创建一个二进制字。因此,如果我们有ABCD(三个连字符),我们创建二进制字000,001,010,011,100,101,110和111.注意,如果我们有n个连字符,我们需要2 ^ n个二进制字。
然后,每个单词通过插入连字符映射到您想要的输出,其中我们有一个&#39; 1&#39;在我们的文字中(000-> ABCD,001-> ABC-D,010-> AB-CD等)。我没有测试上面的代码,但这至少是解决完全连字的问题的一种方法。
免责声明:我没有真正测试代码
答案 4 :(得分:1)
我已经测试了这段代码,它正如问题中指定的那样工作。我将字符串存储在List<string>
。
string str = "AB-C-D-EF-G-HI";
string[] splitted = str.Split('-');
List<string> finalList = new List<string>();
string temp = "";
for (int i = 0; i < splitted.Length; i++)
{
temp += splitted[i];
}
finalList.Add(temp);
temp = "";
for (int diff = 0; diff < splitted.Length-1; diff++)
{
for (int start = 1, limit = start + diff; limit < splitted.Length; start++, limit++)
{
int i = 0;
while (i < start)
{
temp += splitted[i++];
}
while (i <= limit)
{
temp += "-";
temp += splitted[i++];
}
while (i < splitted.Length)
{
temp += splitted[i++];
}
finalList.Add(temp);
temp = "";
}
}