我想知道是否有可以扩展非数字范围的开源库或算法。例如,如果你必须这样1A
做,9A
你应该得到
1A, 2A, 3A, 4A, 5A, 6A, 7A, 8A, 9A.
我已经尝试过谷歌搜索,我能想到的最好的方法是正则表达式,它可以用破折号扩展数字(1-3 变成 1、2、3)。
正如其他人所指出的,更具体会很有用。我不认为您可以期望有一个库可以根据您可以想出的字符串上的任意顺序生成范围。
如果您可以简单地定义任何给定字符串的后继是什么,那么解决方案就很简单了。也就是说,如果您S
在字符串上有一个后继函数(例如 with S('3A') = '4A'
),那么可以使用类似以下的内容:
s = initial_string
while s != final_string do
output s
s = S(s)
output s
我过去用来生成给定长度l
和给定字符范围b
的所有字符串的东西e
是以下(伪)代码。它可以很容易地适应各种变化。
// initialise s with b at every position
for i in [0..l) do
s[i] = b
done = false
while not done do
output s
j = 0
// if s[j] is e, reset it to b and "add carry"
while j < l and s[j] == e do
s[j] = b
j = j + 1
if j == l then
done = true
if not done then
s[j] = s[j] + 1
例如,要从特定字符串开始,您只需要更改初始化。要设置结束,您只需要更改内部 while 的行为即可单独处理位置l
(限制为该位置的结束字符串中的字符,如果达到 decrementing l
)。
我试图让它保持开放,因为可能性的数量是惊人的。我相信,如果没有经过大量技术细节,这里无法 100% 回答的问题之一被认为是“好”或“坏”的范围。我只是想为其他人如何解决这个问题的想法找到一个跳跃点。我希望有人写了一篇博文,解释他们是如何解决这个问题的,或者创建了一个完整的库来处理这个问题。
我想说解决方案的第一步是定义字符和数字如何相互作用并形成一个序列。给定的示例不清楚,因为您至少会假设它运行 1A, 1B .... 8Y, 8Z, 9A - 这是假设您的输入限制为十进制,后跟单个字符。
如果您可以为字符和小数定义一个连续序列,那么您只需进行一些递归/循环即可生成该序列的一部分。
例如,您可以假设输入中的每个字符都是 (1-9A-Z) 之一,因此您可以通过获取 alpha 字符的十进制 ascii 值并减去 55 轻松地使其连续,实际上为您提供范围(1-35)
如果我们假设开始和结束范围将遵循相同的交替模式,并将数字范围限制为0-9
和A-Z
,我们可以将每组数字视为多维坐标中的一个组成部分。例如,1A
将对应于二维坐标(1,A)
(Excel 使用它来标记其二维行和列网格);而AA1BB2
将是一个四维坐标(AA,1,BB,2)
。
因为每个组件都是独立的,要扩展两个坐标之间的范围,我们只需返回每个组件扩展的所有组合。下面是我今天下午准备的一个快速实现。它适用于任意数量的正常和字母数字的交替,并处理大的字母范围(即从AB
到CDE
,而不仅仅是AB
到CD
)。
注意:这是一个实际实现的粗略草案(我明天要起飞,所以它比平时更不完善;)。所有关于错误处理、鲁棒性、(可读性;)等的常见警告都适用。
IEnumerable<string> ExpandRange( string start, string end ) {
// Split coordinates into component parts.
string[] startParts = GetRangeParts( start );
string[] endParts = GetRangeParts( end );
// Expand range between parts
// (i.e. 1->3 becomes 1,2,3; A->C becomes A,B,C).
int length = startParts.Length;
int[] lengths = new int[length];
string[][] expandedParts = new string[length][];
for( int i = 0; i < length; ++i ) {
expandedParts[i] = ExpandRangeParts( startParts[i], endParts[i] );
lengths[i] = expandedParts[i].Length;
}
// Return all combinations of expanded parts.
int[] indexes = new int[length];
do {
var sb = new StringBuilder( );
for( int i = 0; i < length; ++i ) {
int partIndex = indexes[i];
sb.Append( expandedParts[i][partIndex] );
}
yield return sb.ToString( );
} while( IncrementIndexes( indexes, lengths ) );
}
readonly Regex RangeRegex = new Regex( "([0-9]*)([A-Z]*)" );
string[] GetRangeParts( string range ) {
// Match all alternating digit-letter components of coordinate.
var matches = RangeRegex.Matches( range );
var parts =
from match in matches.Cast<Match>( )
from matchGroup in match.Groups.Cast<Group>( ).Skip( 1 )
let value = matchGroup.Value
where value.Length > 0
select value;
return parts.ToArray( );
}
string[] ExpandRangeParts( string startPart, string endPart ) {
int start, end;
Func<int, string> toString;
bool isNumeric = char.IsDigit( startPart, 0 );
if( isNumeric ) {
// Parse regular integers directly.
start = int.Parse( startPart );
end = int.Parse( endPart );
toString = ( i ) => i.ToString( );
}
else {
// Convert alphabetic numbers to integers for expansion,
// then convert back for display.
start = AlphaNumberToInt( startPart );
end = AlphaNumberToInt( endPart );
toString = IntToAlphaNumber;
}
int count = end - start + 1;
return Enumerable.Range( start, count )
.Select( toString )
.Where( s => s.Length > 0 )
.ToArray( );
}
bool IncrementIndexes( int[] indexes, int[] lengths ) {
// Increment indexes from right to left (i.e. Arabic numeral order).
bool carry = true;
for( int i = lengths.Length; carry && i > 0; --i ) {
int index = i - 1;
int incrementedValue = (indexes[index] + 1) % lengths[index];
indexes[index] = incrementedValue;
carry = (incrementedValue == 0);
}
return !carry;
}
// Alphabetic numbers are 1-based (i.e. A = 1, AA = 11, etc, mod base-26).
const char AlphaDigitZero = (char)('A' - 1);
const int AlphaNumberBase = 'Z' - AlphaDigitZero + 1;
int AlphaNumberToInt( string number ) {
int sum = 0;
int place = 1;
foreach( char c in number.Cast<char>( ).Reverse( ) ) {
int digit = c - AlphaDigitZero;
sum += digit * place;
place *= AlphaNumberBase;
}
return sum;
}
string IntToAlphaNumber( int number ) {
List<char> digits = new List<char>( );
while( number > 0 ) {
int digit = number % AlphaNumberBase;
if( digit == 0 ) // Compensate for 1-based alphabetic numbers.
return "";
char c = (char)(AlphaDigitZero + digit);
digits.Add( c );
number /= AlphaNumberBase;
}
digits.Reverse( );
return new string( digits.ToArray( ) );
}