【问题标题】:How do I generate the shortest database identifier names from a number?如何从数字生成最短的数据库标识符名称?
【发布时间】:2015-12-25 06:09:49
【问题描述】:

因为我正在编写的软件会生成带有大量参数的 SQL,并将这些 SQL 记录到磁盘上,所以我有一个不常见的要求(也许更多的是好奇):生成尽可能短的唯一参数名称。

参数名称遵循标识符命名规则,通常是:

  1. 第一个字符是字母
  2. 后续字符可以是字母数字或某些其他字符,例如下划线。
  3. 如果引用,几乎可以使用任何东西(忽略 - 引用的标识符总共至少三个字符,例如 [_]

SQL 生成代码知道总共有多少个标识符,因此可以根据整数生成名称。

【问题讨论】:

    标签: c# sql dynamic-sql uniqueidentifier identifier


    【解决方案1】:

    Timur Mannapov 的回答产生了与我的其他一些尝试类似的结果(除了他的结果没有 cmets 中指出的问题),因为进展不是人们所期望的,例如aa, ba, ca 而不是 aa, ab, ac: (拨打String.Concat(ToParamName(i))

    // Starts with aa, ba, ba... instead of a, b, c. Probably wouldn't be hard
    // to fix but I abandoned this method because it's annoying to call using
    // string.Concat(...)
    public static IEnumerable<char> ToParamName(int number) {
        const string characters = "abcdefghijklmnopqrstuvwxyz0123456789";
        yield return characters[number % 26];
        number = number / 26;
        do {
            yield return characters[number % 36];
            number = number / 36 - 1;
        } while(number >= 0);
    }
    
    
    // Starts with a, b, c...aa, ba, ba but has collisions starting around 960
    public static IEnumerable<char> ToParamName(int number) {
        const string characters = "abcdefghijklmnopqrstuvwxyz0123456789";
        yield return characters[number % 26];
        number = number / 26;
        while(number > 0) {
            yield return characters[number % 36];
            number = number / 36 - 1;
        }
    }
    

    我更喜欢以更自然的顺序返回结果,例如 a..z, aa, ab, ac...a9(嘿,我并没有声称我是纯粹实用的),但我忘了在原始帖子中提及这一点。 Timur 的回答涵盖了所有原始要求,因此我将其标记为正确。

    我将 +1 一个产生所描述结果的答案。

    【讨论】:

      【解决方案2】:

      上面的代码会产生冲突。修复了没有冲突和幻数的代码。

          public static String intToDatabaseIdentifier(int number)
          {
              const string abcFirst = "abcdefghijklmnopqrstuvwxyz";
              const string abcFull = "abcdefghijklmnopqrstuvwxyz0123456789";
              if (number < 0 || number > 1000000)
                  throw new ArgumentOutOfRangeException("number");
              var stack = new Stack<char>();
              //Get first symbol. We will later reverse string. So last - will be first. 
              stack.Push(abcFirst[number % abcFirst.Length]);
              number = number / abcFirst.Length;
              //Collect remaining part
              while (number > 0)
              {
                  int index = (number - 1) % abcFull.Length;
                  stack.Push(abcFull[index]);
                  number = (number - index) / abcFull.Length;
              }
              //Reversing to guarantee first non numeric.
              return new String(stack.Reverse().ToArray());
          }
      

      【讨论】:

      • 干得好!如果您可以产生类似a..z, aa, ab, ac...a9 的结果,则另加 1
      【解决方案3】:

      这最终比我预期的要困难,而且解决方案也不那么优雅。 我对无效值进行了硬编码(以0 开头),因为它们很少,而且我为导出它们所做的每一次尝试最终都变得复杂而缓慢。我会很感激关于如何使它更优雅的想法。我也会在 CodeReview 上发帖。

      大多数数据库支持少于 2^16 个参数(实际使用的数字很荒谬),但在处理大于 35027 的数字时(也很荒谬),100 万是一个很好的强制停止点。

      public static String intToDatabaseIdentifier(int number)
      {
          if(number < 0 || number > 1000000)
              throw new ArgumentOutOfRangeException("number");
          if(number > 25 && number <= 25 + 10) // Skip 0-9 (modified base 36)
              number += 10;
          if(number > 971 && number <= 971 + 360) // Skip 0a-09 (modified base 36)
              number += 360;
          if(number > 35027 && number <= 35027 + 12960) // Skip 0aa-099 (modified base 36)
              number += 12960;
          var stack = new Stack<char>();
          // Base 36 starting with letters rather than numbers
          const string characters = "abcdefghijklmnopqrstuvwxyz0123456789";
          while(number >= 0) {
              stack.Push(characters[number % 36]);
              number = number / 36 - 1;
          }
          return new String(stack.ToArray());
      }
      

      从 0 开始的结果:

      a b c d e f g h i j k l m n o p q r s t u v w x y z
      aa ab ac ad ae af ag ah ai aj aa ab ac ad ae af ag ah ai aj ak al am an ao
      ap aq ar as at au av aw ax ay az a0 a1...
      

      【讨论】:

      • 也许您可以将数据库允许的字符添加到允许的字符中。我注意到您已遵循标识符不能以数字开头的规则。这里提到的stackoverflow.com/a/20004348/511438 是@、下划线、英镑和美元。
      • 没错,这很容易做到,尽管它可能会降低与数据库无关的风险。
      • 似乎您的代码会产生冲突。试试 26 和 36。
      • @TimurMannapov 是的,到处都是碰撞,每次添加if(range)...workaround 行时我都要洗个澡。
      猜你喜欢
      • 1970-01-01
      • 2022-12-09
      • 1970-01-01
      • 1970-01-01
      • 2018-01-30
      • 1970-01-01
      • 2016-07-23
      • 2021-04-13
      • 2020-11-07
      相关资源
      最近更新 更多