Библиотека или алгоритм взрыва буквенно-цифрового диапазона - PullRequest
1 голос
/ 05 сентября 2008

Мне было интересно, есть ли библиотека с открытым исходным кодом или алгоритм, который может расширить нечисловой диапазон. Например, если у вас есть 1A до 9A, вы должны получить

1A, 2A, 3A, 4A, 5A, 6A, 7A, 8A, 9A.

Я попробовал Googling для этого, и лучшее, что я мог придумать, это Regex, который расширил бы числа с черточками (1-3 - 1,2,3).

Ответы [ 4 ]

1 голос
/ 06 сентября 2008

Как отмечают другие, было бы полезно быть более конкретным. Я не думаю, что вы можете ожидать, что будет библиотека, которая будет генерировать диапазоны в соответствии с любым произвольным порядком в строке, которую вы можете придумать.

Если вы можете просто определить, что является преемником любой заданной строки, то решения довольно просты. То есть, если у вас есть функция-преемник S для строк (например, с 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

Например, чтобы начать с определенной строки, вам нужно только изменить инициализацию. Чтобы установить конец, вам нужно всего лишь изменить поведение внутреннего элемента, в то время как отдельно обрабатывать позицию l (ограничение до символа в конечной строке в этой позиции и, если достигнуто, уменьшение l).

0 голосов
/ 05 сентября 2008

Я бы сказал, что первым шагом в решении будет определение того, как символы и числа взаимодействуют и образуют последовательность. Данный пример не ясен, так как вы, по крайней мере, предполагаете, что он работает 1A, 1B .... 8Y, 8Z, 9A - при условии, что ваш ввод ограничен десятичным числом, за которым следует один символ.

Если вы можете определить непрерывную последовательность для символов и десятичных чисел, тогда вам просто потребуется рекурсия / циклическое создание части этой последовательности.

Например, вы можете предположить, что каждый символ на входе является одним из (1-9A-Z), поэтому вы можете легко сделать это непрерывным, взяв десятичное значение ascii буквенных символов и вычитая 55, что дает Вы диапазон (1-35)

0 голосов
/ 06 сентября 2008

Если мы предположим, что начальный и конечный диапазоны будут следовать одному и тому же знакопеременному образцу и ограничить диапазон цифр 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( ) );
}
0 голосов
/ 05 сентября 2008

Я пытался оставить это несколько открытым, потому что количество возможностей ошеломляет. Я полагаю, что этот один из тех вопросов, на которые нельзя ответить здесь 100%, не пройдя много технических деталей, считается «хорошим» или «плохим» диапазоном. Я просто пытаюсь найти точку отсчета для идей о том, как другие люди решили эту проблему. Я надеялся, что кто-то написал сообщение в блоге, объясняющее, как они решили эту проблему или создали целую библиотеку для решения этой проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...