通过将占位符替换为输入集的所有排列,从模板创建字符串



我想做一个简单的字符串生成器。

用户输入字符串的"模板"。模板可以在其中的任何位置包含占位符。 然后,他输入可以放入字符串中任何占位符的可能字符。 它应该如何工作:

输入:

a.b.
123

输出:

[
"a1b1", "a1b2", "a1b3",
"a2b1", "a2b2", "a2b3",
"a3b1", "a3b2", "a3b3"
]

我找到了一些旧的python代码,但我完全不明白。

我将输入字符串拆分为字符串数组和点数组。 然后我尝试只增加点,每次都以正确的方式连接这两个数组。 但我发现了一个新的麻烦。

string[] splitted = kt_NonCur.Split('.');   // array of constant strings
char[] nch = new char[splitted.Length - 1]; // array of new chars (generated)
char lgc = goodLetters.Last( );    // last good char
for( int i = 0; i < nch.Length - 1; i++ ) // set up all nch to first letter
nch[i] = goodLetters[0];
while( nch.Last( ) != lgc ) {  // until last nch is set to last good char
outputData.Add($"{concatsplit(splitted, nch)}"); // concatsplit(s,n) concatenates two arrays into string
nch[0] = up(nch[0]); // up(char) gets next character from goodLetters. If there is no next, it returns first letter.
if( nch[0] == goodLetters[0] ) {
nch[1] = up(nch[1]);    
if(nch[1] == goodLetters[0]){
nch[2] = up(nch[2]);
//                          .
//                              .
//                                  .
}
}
}

问题是:我正面临一个两难境地。要么找到更好的方法,要么限制占位符的数量,以便代码梯不会太长。当然,我会添加一些代码来检查它是否是最后一个并停止为其他人执行代码,但我仍然必须制作

你可以这样看你的问题:如果你的输入字符串中有 P 占位符,并且替换字符的数量是 R,则在每个步骤中构造你需要的每个可能的输出字符串 P 数字 [0...R-1](然后可以作为替换字符列表的索引(。好吧,这是以 R 为底的 P 位整数的定义。

因此,让我们编写一个表示此类整数的帮助程序类:

class NDigitNumber
{
int[] _digits;
int _base;
// construct an integer with the specified numer of digits in the specified base
public NDigitNumber(int digits, int @base)
{
_digits = new int[digits];
_base = @base;
}
// get the digit at the specified position
public int this[int index] => _digits[index];
// increment the number, returns false on overflow
public bool Increment()
{
for (var pos = 0; pos < _digits.Length; pos++)
{
if (++_digits[pos] < _base)
break;
if (pos == _digits.Length-1)
return false;
for (var i = 0; i <= pos; i++)
_digits[i] = 0;
}
return true;
}
}

增量方法的工作方式类似于这些机械计数器设备,其中每个数字轮在从其最大数字旋转到下一个数字时,将自身和所有下轮重置为 0 并递增下一个较高的轮子。

然后我们只需要遍历所有可能的此类整数即可获得所需的输出:

var input = "a.b.";
var placeholder = '.';
var replacements = new[] { '1', '2', '3' };
// determine positions of placeholder in string
var placeholderPositions = new List<int>();
for (var i = 0; i < input.Length; i++)
{
if (input[i] == placeholder)
placeholderPositions.Add(i);
}
// iterate over all possible integers with
// placeholderPositions.Count digits
// in base replacements.Length
var number = new NDigitNumber(placeholderPositions.Count, replacements.Length);
do
{
var result = new StringBuilder(input);
for (var i = 0; i < placeholderPositions.Count; i++)
result[placeholderPositions[i]] = replacements[number[i]];
Console.WriteLine(result.ToString());
} while(number.Increment());

输出:

a1b1
a2b1
a3b1
a1b2
a2b2
a3b2
a1b3
a2b3
a3b3

基于这篇文章的公认答案:

public static IEnumerable<string> Combinations(string template, string str, char placeholder)
{
int firstPlaceHolder = template.IndexOf(placeholder);   
if (firstPlaceHolder == -1)     
return new string[] { template };
string prefix = template.Substring(0, firstPlaceHolder);    
string suffix = template.Substring(firstPlaceHolder + 1);   

var recursiveCombinations = Combinations(suffix, str, placeholder);
return
from chr in str
from recSuffix in recursiveCombinations
select prefix + chr + recSuffix;
}

用法:

List<string> combinations = Combinations("a.b.", "123", '.').ToList();

最新更新