【问题标题】:Permutations of capitalization大小写排列
【发布时间】:2009-05-25 04:31:47
【问题描述】:

我想建立一个列表,其中包含单词大写的所有可能排列。所以会是

List<string> permutate(string word)
{
    List<string> ret = new List<string>();
    MAGIC HAPPENS HERE
    return ret;
}

所以说我输入了"happy" 我应该得到一个数组返回

{happy, Happy, hAppy, HAppy, haPpy, HaPpy ... haPPY, HaPPY, hAPPY, HAPPY}

我知道有很多函数会将第一个字母大写,但我如何在单词中任意输入字母?

【问题讨论】:

  • 我只是想知道这是为了什么。如果是出于任何比较目的,那可能是解决问题的错误方法。
  • 这可能是字典攻击。
  • 实际上是,我忘记了文件密码,我知道单词但不知道大小写。我的计划是计算每一个可能的值并将其输入字典破解器。

标签: c# .net string capitalization


【解决方案1】:

如果将字符串转换为 char 数组,则可以修改单个字符。像这样的东西应该可以解决问题......

public static List<string> Permute( string s )
{
  List<string> listPermutations = new List<string>();

  char[] array = s.ToLower().ToCharArray();
  int iterations = (1 << array.Length) - 1;

  for( int i = 0; i <= iterations; i++ )
  {
    for( int j = 0; j < array.Length; j++ )
    array[j] = (i & (1<<j)) != 0 
                  ? char.ToUpper( array[j] ) 
                  : char.ToLower( array[j] );
    listPermutations.Add( new string( array ) );
  }
  return listPermutations;
}

【讨论】:

  • 我在循环之前添加了一个 listPermutatuions.Add,这样它就可以存储一个完全小写的版本,而不是你的完美运行。
  • 这不会返回所有这些。例如,“快乐”。实际上,总共应该有 2^n 个,而上面的代码只产生 n(n+1)/2 + 1 个。
  • 这就是为什么您应该始终测试您的代码......以及为什么开源如此有效。谢谢新账户。这次我实际上花时间测试了实现......它确实产生了所有 2^n 排列。
  • 如果我只想要字符串中某些字符的大小写变化怎么办?例如,考虑一个字符串“abcd”,我只想要“bd”的大小写变体,我会得到“abcd”、“aBcd”、“aBcD”和“abcD”。有什么建议吗?
【解决方案2】:

请记住,虽然接受的答案是将任意字母大写的最直接的方法,但如果您要在同一组字母上反复更改大写(例如,“happy”中的 32 次并成倍增长较长的单词),将字符串转换为 char[],设置适当的字母,并从数组中构造字符串会更有效。

【讨论】:

  • 这让我想知道......如果你创建一个二维数组,索引 0 是小写单词,索引 1 是大写单词(作为 char 数组)。然后你可以从 0 迭代到 2^(word_length-1) 并使用整数的位来告诉你从哪个数组中获取每个字母。我真的不知道这是否是个好主意。当我读到这篇文章时,我突然想到了。
  • 从概念上讲,我就是这样做的(位测试部分),但我修改了一个数组。更好的是使用格雷码,以便可以使用 2^(word_length)-1 “大小写翻转”生成整个数组。
  • 使用 GrayCode 有什么好处?每次迭代只翻转一位是否更有效?您将如何使用格雷码?使用整数的常规二进制编码很容易,因为您可以使用按位运算来检查 int 中设置了哪些位,但是如何获得每个 int 的 GrayCode 位串
【解决方案3】:

要“置换”你的字符串(从技术上讲,这不是置换,因为你没有改变任何东西的顺序,但我不想被视为一个 *l-retentive :-),我会使用递归方法,它基本上“置换”字符串减去第一个字符,并将它们附加到该字符的上下变化。

类似的东西(在 C 中,我的 C# 并没有真正达到标准,所以你必须转换它):

#include <stdio.h>
#include <string.h>

static void permute (char *prefix, char *str) {
    char *newPrefix;

    /* End of string, print and return. */

    if (*str == '\0') {
        printf ("%s\n", prefix);
        return;
    }

    /* Allocate space for new prefix. */

    if ((newPrefix = malloc (strlen (prefix) + 2)) == NULL) {
        printf ("ERROR: Cannot allocate memory.\n");
        return;
    }

    /* Do lowercase/sole version and upper version if needed. */

    sprintf (newPrefix, "%s%c", prefix, *str);
    permute (newPrefix, &(str[1]));

    if (islower (*str) {
        sprintf (newPrefix, "%s%c", prefix, toupper(*str));
        permute (newPrefix, &(str[1]));
    }

    /* Free prefix and return. */

    free (newPrefix);
}

 

int main (int argc, char *argv[]) {
    char *str, *strPtr;

    /* Check and get arguments. */

    if (argc < 2) {
        printf ("Usage: permute <string to permute>\n");
        return 1;
    }

    if ((str = malloc (strlen (argv[1]) + 1)) == NULL) {
        printf ("ERROR: Cannot allocate memory.\n");
        return 1;
    }
    strcpy (str, argv[1]);

    /* Convert to lowercase. */
    for (strPtr = s; *strPtr != '\0'; strPtr++)
        *strPtr = toupper (*strPtr);

    /* Start recursion with empty prefix. */

    permute ("", str);

    /* Free and exit. */

    free (str);
    return 0;
}

"permute Pax1" 运行此返回:

pax1
paX1
pAx1
pAX1
Pax1
PaX1
PAx1
PAX1

【讨论】:

    【解决方案4】:

    我能够创建一个执行此操作的控制台应用程序..

     public static class Program
    {
        static void Main()
        {
            Console.WriteLine("Enter string");
            string value = Console.ReadLine();
    
            value = value.ToLower();
    
            List<string> list = new List<string>();
    
             var results =
                 from e in Enumerable.Range(0, 1 << value.Length)
                 let p =
                 from b in Enumerable.Range(0, value.Length)
                 select (e & (1 << b)) == 0 ? (char?)null : value[b]
                 select string.Join(string.Empty, p);
    
            foreach (string s in results)
            {
                string newValue = value;
                s.ToLower();
                foreach(char c in s)
                {
                    var Old = c.ToString().ToLower();
                    var New = c.ToString().ToUpper();
                    newValue=ReplaceFirstOccurrence(newValue, Old, New);
                }
                list.Add(newValue);
            }
    
            foreach(string s in list)
            {
                Console.WriteLine(s);
            }
    
            Console.ReadKey();
        }
    
        public static string ReplaceFirstOccurrence(string Source, string Find, string Replace)
        {
            int Place = Source.IndexOf(Find);
            string result = Source.Remove(Place, Find.Length).Insert(Place, Replace);
            return result;
        }    
    }

    我得到了字符串中所有可能的字符子集的列表,然后对于每个子集中的每个字符,将它们替换为初始字符串中的大写对应字符,然后列出这些字符。必须有一个自定义替换函数作为普通字符串。替换将替换任何出现的字符。

    它可能不是最干净的代码,但它可以完成工作。这是作为动态搜索加密字段的一种手段提出来的,我想看看这到底有多疯狂..

    【讨论】:

      【解决方案5】:

      如果顺序没关系,你可以试试Linq。我们枚举[0..2**word.Length] 范围内的所有二进制数。并将每个数字视为掩码0 - 小写,1 - 大写。例如happy 我们有

      mask      string
      ----------------
      00000  ->  happy
      00001      Happy
      00010      hAppy
      00011      HAppy
      00100      haPpy
      00101      HaPpy
      ...
      11111      HAPPY
      

      代码:

        using System.Linq;
      
        ... 
      
        List<string> permutate(string word) =>
          Enumerable
            .Range(0, 1 << word.Length)
            .Select(mask => string.Concat(word.Select((c, i) => (mask & (1 << i)) == 0 
               ? char.ToLower(c) 
               : char.ToUpper(c))))
            .ToList();
      

      演示:

        Console.Write(string.Join(", ", permutate("happy")));
      

      结果:

      happy, Happy, hAppy, HAppy, haPpy, HaPpy, hAPpy, HAPpy, hapPy, HapPy, hApPy, HApPy, haPPy, HaPPy, hAPPy, HAPPy, happY, HappY, hAppY, HAppY, haPpY, HaPpY, hAPpY, HAPpY, hapPY, HapPY, hApPY, HApPY, haPPY, HaPPY, hAPPY, HAPPY 
      

      【讨论】:

        【解决方案6】:

        简单地说,如下所示。我可能会将我的范围缩小一倍,但这个想法是合理的。

        def cap_n(in_str, pos):
          leading = in_str.substr(0, pos-1)
          trailing = in_str.substr(pos+1) # no second arg implies to end of string
          chr = in_str[pos].to_uppercase()
          return leading + chr + trailing
        

        【讨论】:

          【解决方案7】:

          使用按位运算。对于长度为 N 的单词,您需要一个由 N 位表示的整数类型。如果单词更长 - 拆分它。遍历从 0 到 2N-1 的值并检查从 0 到 N-1 的每个位。如果该位为 1 - 大写 (Char.ToUpper()),则该位对应的字母。

          这种方法比递归算法更好,因为它不容易在长字上发生堆栈溢出。

          【讨论】:

            【解决方案8】:

            假设:

            1) 你不太在意这是 O(n*2^n)...虽然我很想知道:对于这类问题,最佳渐近运行时间是多少?

            2) 你的输入都是小写的。

            3) 您的输入长度小于 32 个字符。 (排列计数器中可用位的数量,i)

                List<string> permutate(string word)
            {
                List<string> ret = new List<string>();
            
            // MAGIC HAPPENS HERE
            Dictionary<char,char> toUppers = new Dictionary<char,char>(26);
            toUppers.Add('a', 'A');
            toUppers.Add('b', 'B');
            toUppers.Add('c', 'C');
            toUppers.Add('d', 'D');
            toUppers.Add('e', 'E');
            toUppers.Add('f', 'F');
            toUppers.Add('g', 'G');
            toUppers.Add('h', 'H');
            toUppers.Add('i', 'I');
            toUppers.Add('j', 'J');
            toUppers.Add('k', 'K');
            toUppers.Add('l', 'L');
            toUppers.Add('m', 'M');
            toUppers.Add('n', 'N');
            toUppers.Add('o', 'O');
            toUppers.Add('p', 'P');
            toUppers.Add('q', 'Q');
            toUppers.Add('r', 'R');
            toUppers.Add('s', 'S');
            toUppers.Add('t', 'T');
            toUppers.Add('u', 'U');
            toUppers.Add('v', 'V');
            toUppers.Add('w', 'W');
            toUppers.Add('x', 'X');
            toUppers.Add('y', 'Y');
            toUppers.Add('z', 'Z');
            
            char[] wordChars = word.ToCharArray();
            int len = wordChars.Length;
            
            // iterate the number of permutations
            for(int i = 0; i < 2^len; i++) {
                char[] newWord = new char[len]();
            
                // apply "i" as a bitmask to each original char
                for(int n = 0; n < newWord.Length; n++) {
                    if((1 << n) & i != 0) {
                        newWord[n] = toUppers[wordChars[n]]; // or skip the dictionary and just call Char.ToUpper(wordChars[n])
                    } else {
                        newWord[n] = wordChars[n];
                    }
                }
                ret.Add(new String(newWord));
            }
            
                return ret;
            }
            

            注意:我没有编译或测试过这段代码。这也实现了上述尖牙建议的按位比较。

            【讨论】:

              猜你喜欢
              • 2021-12-15
              • 2011-10-10
              • 1970-01-01
              • 1970-01-01
              • 2012-12-04
              • 2019-02-06
              • 2013-06-20
              相关资源
              最近更新 更多