2011-03-22 120 views
1

我有一个小项目,我有一个输入的句子它有可能为用户指定的变化:如何生成一整套字符串操作的组合?

The {small|big} car is {red|blue} 

上面是一个例句我想分成4个句子,像这样:

  • 的小型车是红色的
  • 大汽车是红色的
  • 的小型车是蓝色
  • 大汽车是蓝色

我似乎无法绕过这个问题。也许有人可以帮我。

编辑 这是我最初的代码

Regex regex = new Regex("{(.*?)}", RegexOptions.Singleline); 
MatchCollection collection = regex.Matches(richTextBox1.Text); 
string data = richTextBox1.Text; 

//build amount of variations 
foreach (Match match in collection) 
{ 
    string[] alternatives = match.Value.Split(new char[] { '|', '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 
    foreach (string alternative in alternatives) 
    { 
     //here i get problems     
    } 
} 
+1

你尝试过这么远吗? ([提示](http://msdn.microsoft.com/en-us/library/ch45axte.aspx)) – 2011-03-22 14:06:05

+0

你看过正则表达式吗? – 2011-03-22 14:07:48

+0

您错过了作业标签吗? – 2011-03-22 14:08:41

回答

3

这听起来像你需要为这个动态笛卡尔功能。 Eric Lippert的blog post是为响应Generating all Possible Combinations而写的。

首先,我们需要解析输入字符串:

Regex ex = new Regex(@"(?<=\{)(?<words>\w+(\|\w+)*)(?=\})"); 
var sentence = "The {small|big} car is {red|blue}"; 

然后输入字符串应该修改string.Format样的功能使用:

int matchCount = 0; 
var pattern = ex.Replace(sentence, me => 
{ 
    return (matchCount++).ToString(); 
}); 
// pattern now contains "The {0} car is {1}" 

那么我们就需要找到所有匹配并申请Eric的优秀CartesianProduct扩展方法:

var set = ex.Matches(sentence) 
    .Cast<Match>() 
    .Select(m => 
     m.Groups["words"].Value 
      .Split('|') 
    ).CartesianProduct(); 

foreach (var item in set) 
{ 
    Console.WriteLine(pattern, item.ToArray()); 
} 

这将产生:

The small car is red 
The small car is blue 
The big car is red 
The big car is blue

,最后,该CartesianProduct方法(从here拍摄):

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
    this IEnumerable<IEnumerable<T>> sequences) 
{ 
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
    return sequences.Aggregate( 
    emptyProduct, 
    (accumulator, sequence) => 
     from accseq in accumulator 
     from item in sequence 
     select accseq.Concat(new[] {item}));     
} 
+1

这很美! – 2011-03-22 15:25:35

+0

哇。我认为我越来越擅长c#,然后我看到这样的答案提醒我我还有很多东西需要学习。 – 2011-03-23 14:26:37

-1
string color = SomeMethodToGetColor(); 
string size = SomeMethodToGetSize(); 

string sentence = string.Format("The {0} car is {1}", size, color); 
+0

我没有看到此解决方案?在我的句子中没有指定具体数量的变体,它可以不是或可以是几个。 – 2011-03-22 14:12:42

+0

这个问题有4个句子。唯一的选择是尺寸和颜色。我可能会误解你的问题。你是说用户用自由形式的文本输入完整的句子吗?即一个文本框来输入整个句子? – 2011-03-22 14:22:53

+0

没有冒犯,但这根本没有帮助。 H4mm3rHead想要确定所有可能的组合。 – 2011-03-22 14:23:06

0

我提议输入文本分成静态和动态部分的有序列表。每个动态部分本身都包含一个存储其值的列表和一个表示当前选定值的索引。该指数初始设定为零。

要打印出所有可能的组合,首先必须实现一个方法,该方法使用动态部分的当前设置索引打印完整列表。对于第一次调用,所有索引都将设置为零。

现在您可以递增第一个动态部分的索引并打印完整列表。这会给你第一个变化。重复此操作,直到您打印剩余动态部分的所有可能值。

+0

Off topic:这将是一个很好的练习,我的课程在C编程:) – 2011-03-22 14:19:31

0

考虑嵌套迭代循环。喜欢的东西...

foreach(string s in someStringSet) 
{ 
    foreach(string t in someOtherStringSet) 
    { 
     // do something with s and t 
    } 
} 
3
private void ExpandString(List<string> result, string text) 
    { 
     var start = text.IndexOf('{'); 
     var end = text.IndexOf('}'); 
     if (start >= 0 && end > start) 
     { 
      var head = text.Substring(0, start); 
      var list = text.Substring(start + 1, end - start - 1).Split('|'); 
      var tail = text.Substring(end + 1); 
      foreach (var item in list) 
       ExpandString(result, head + item + tail); 
     } 
     else 
      result.Add(text); 
    } 

使用像:

var result = new List<string>(); 
    ExpandString(result, "The {small|big} car is {red|blue}"); 
+0

尼斯和紧凑... – 2011-03-22 14:40:46

+0

测试和完美的作品。 – 2011-03-22 14:45:35

+0

{{是sentince的第一个字符! 改变“如果(开始> 0”到“> =”修复问题 – 2011-03-22 14:53:31

0

也许你正在寻找这样的: 编辑的版本

static void Main(string[] args) 
{ 
    var thisstring = "The {Small|Big} car is {Red|Blue}";   
    string FirstString = thisstring.Substring(thisstring.IndexOf("{"), (thisstring.IndexOf("}") - thisstring.IndexOf("{")) + 1); 
    string[] FirstPossibility = FirstString.Replace("{", "").Replace("}", "").Split('|'); 
    thisstring = thisstring.Replace(FirstString, "[0]"); 
    string SecondString = thisstring.Substring(thisstring.IndexOf("{"), (thisstring.IndexOf("}") - thisstring.IndexOf("{")) + 1); 
    string[] SecondPosibility = SecondString.Replace("{", "").Replace("}", "").Split('|'); 
    thisstring = thisstring.Replace(SecondString, "{1}").Replace("[0]", "{0}"); 
    foreach (string tempFirst in FirstPossibility) 
    { 
     foreach (string tempSecond in SecondPosibility) 
     { 
      Console.WriteLine(string.Format(thisstring, tempFirst, tempSecond)); 
     } 
    } 
    Console.Read(); 
} 
1

如果你不”吨知道变化的数量,递归是你的朋友:

static public IEnumerable<string> permute(string template) 
{ 
    List<string> options; 
    string before; 
    string after; 
    if (FindFirstOptionList(template, out options, out before, out after)) 
    { 
     foreach (string option in options) 
     { 
      foreach (string permutation in permute(before + option + after)) 
      { 
       yield return permutation; 
      } 
     } 
    } 
    else 
    { 
     yield return template; 
    } 
} 

static public bool FindFirstOptionList(string template, out List<string> options, out string before, out string after) 
{ 
    before = string.Empty; 
    after = string.Empty; 
    options = new List<string>(0); 
    if (template.IndexOf('{') == -1) 
    { 
     return false; 
    } 
    before = template.Substring(0, template.IndexOf('{')); 
    template = template.Substring(template.IndexOf('{') + 1); 
    if (template.IndexOf('}') == -1) 
    { 
     return false; 
    } 
    after = template.Substring(template.IndexOf('}') + 1); 
    options = template.Substring(0, template.IndexOf('}')).Split('|').ToList(); 
    return true; 
} 

使用类似于danbystrom的解决方案,除了这个方法返回一个IEnumerable,而不是操纵调用的参数之一。当心语法错误等

static void main() 
{ 
    foreach(string permutation in permute("The {small|big} car is {red|blue}")) 
    { 
     Console.WriteLine(permutation); 
    } 
} 
0

像这样的东西应该工作:

private void Do() 
{ 
    string str = "The {small|big} car is {red|blue}"; 

    Regex regex = new Regex("{(.*?)}", RegexOptions.Singleline); 

    int i = 0; 
    var strWithPlaceHolders = regex.Replace(str, m => "{" + (i++).ToString() + "}"); 

    var collection = regex.Matches(str); 

    var alternatives = collection.OfType<Match>().Select(m => m.Value.Split(new char[] { '|', '{', '}' }, StringSplitOptions.RemoveEmptyEntries)); 
    var replacers = GetReplacers(alternatives); 

    var combinations = new List<string>(); 
    foreach (var replacer in replacers) 
    { 
     combinations.Add(string.Format(strWithPlaceHolders, replacer)); 
    } 
} 

private IEnumerable<object[]> GetReplacers(IEnumerable<string[]> alternatives) 
{ 
    return GetAllPossibilities(0, alternatives.ToList()); 
} 

private IEnumerable<object[]> GetAllPossibilities(int level, List<string[]> list) 
{ 
    if (level == list.Count - 1) 
    { 
     foreach (var elem in list[level]) 
      yield return new[] { elem }; 
    } 
    else 
    { 
     foreach (var elem in list[level]) 
     { 
      var thisElemAsArray = new object[] { elem }; 
      foreach (var subPossibilities in GetAllPossibilities(level + 1, list)) 
       yield return thisElemAsArray.Concat(subPossibilities).ToArray(); 
     } 
    } 
    yield break; 
} 
相关问题