【问题标题】:Library or algorithm to explode an alphanumeric range扩展字母数字范围的库或算法
【发布时间】:2008-09-05 12:25:13
【问题描述】:

我想知道是否有可以扩展非数字范围的开源库或算法。例如,如果你有 1A9A 你应该得到 ​​p>

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

我已经尝试用谷歌搜索,我能想到的最好的方法是正则表达式,它可以用破折号扩展数字(1-3 变成 1,2,3)。

【问题讨论】:

    标签: .net algorithm


    【解决方案1】:

    正如其他人所指出的,更具体会很有用。我不认为你可以期望有一个库会根据你能想到的字符串上的任意顺序生成范围。

    如果您可以简单地定义任何给定字符串的后继是什么,那么解决方案就很简单了。也就是说,如果你在字符串上有一个后继函数S(例如S('3A') = '4A'),那么可以使用类似下面的东西:

    s = initial_string
    while s != final_string do
      output s
      s = S(s)
    output s
    

    我过去用来生成给定长度l 和给定范围be 字符的所有字符串的东西是以下一段(伪)代码。它可以轻松适应各种变化。

    // 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(限制在该位置的结束字符串中的字符,如果达到则递减 l)。

    【讨论】:

    • 只想提一下,如果您认为问题是线性的(即将A1B2 视为单个数字),这是一个很好的解决方案。我仍然认为问题是多维的,但我想我们只需要等待作者澄清:)
    【解决方案2】:

    我试图让它保持开放,因为可能性的数量是惊人的。我相信,如果没有经过大量技术细节,这里无法 100% 回答的问题之一被认为是“好”或“坏”的范围。我只是想为其他人如何解决这个问题的想法找到一个跳跃点。我希望有人写了一篇博文,解释他们是如何解决这个问题的,或者创建了一个完整的库来处理这个问题。

    【讨论】:

      【解决方案3】:

      我想说解决方案的第一步是定义字符和数字如何相互作用并形成一个序列。给定的示例不清楚,因为您至少会假设它运行 1A, 1B .... 8Y, 8Z, 9A - 这是假设您的输入限制为十进制,后跟单个字符。

      如果您可以为字符和小数定义一个连续序列,那么您只需进行一些递归/循环即可生成该序列的一部分。

      例如,您可以假设输入中的每个字符都是 (1-9A-Z) 之一,因此您可以通过获取字母字符的十进制 ascii 值并减去 55 轻松地使其连续,实际上给出你的范围(1-35)

      【讨论】:

        【解决方案4】:

        如果我们假设开始和结束范围将遵循相同的交替模式,并将数字范围限制为 0-9A-Z,我们可以将每组数字视为多维中的一个组成部分协调。例如,1A 将对应于二维坐标(1,A)(Excel 使用它来标记其二维行和列网格);而AA1BB2 将是一个四维坐标(AA,1,BB,2)

        因为每个组件都是独立的,所以要扩展两个坐标之间的范围,我们只需返回每个组件扩展的所有组合。下面是我今天下午准备的一个快速实现。它适用于任意数量的普通数字和字母数字的交替,并处理较大的字母范围(即从ABCDE,而不仅仅是ABCD)。

        注意:这是一个实际实现的粗略草案(我明天就要起飞了,所以它比平时更不完善;)。所有关于错误处理、鲁棒性、(可读性;)等的常见警告都适用。

        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( ) );
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-12
          • 2012-05-30
          • 2023-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-05
          相关资源
          最近更新 更多