Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 字符串中的随机字符-具有多字节字符_C#_String_Char_Multibyte - Fatal编程技术网

C# 字符串中的随机字符-具有多字节字符

C# 字符串中的随机字符-具有多字节字符,c#,string,char,multibyte,C#,String,Char,Multibyte,A之前被询问过,但这是不同的,因为我试图从中提取随机字符的字符串可能包含多字节字符。我基本上是在制作一个伪“leet”生成器,它接受一个字符串并将所有字符从扩展的Unicode中随机选择,看起来很相似,给它一种“黑客”类型的外观。(这是一个游戏,一个部分需要使用这种风格。不要评判我。)所以我有一个扩展方法: private static Random rand = new Random(); public static char random(this string str) { ret

A之前被询问过,但这是不同的,因为我试图从中提取随机字符的字符串可能包含多字节字符。我基本上是在制作一个伪“leet”生成器,它接受一个字符串并将所有字符从扩展的Unicode中随机选择,看起来很相似,给它一种“黑客”类型的外观。(这是一个游戏,一个部分需要使用这种风格。不要评判我。)所以我有一个扩展方法:

private static Random rand = new Random();
public static char random(this string str)
{
    return str[rand.Next(str.Length)];
}
它的工作方式是,我查看字符串中的每个字符,它的名称如下:

public static string leetify(this string str)
{
    StringBuilder sb = new StringBuilder();

    foreach (char c in str)
    {
        switch (char.ToLower(c))
        {
            case 'a':
                sb.Append("4ÀÁÂÃÄÅàáâãäåĀāĂ㥹ǎǍǺǻȀȁȂȃȦȧȺɅɐɑɒªΆѦѧᴀᾼ₳".random());
                break;
                ...  //More of the same for each letter

                //Okay, the letter 's' definitely has a failure case,
                //not the only one, but needed an example
            case 's':
                sb.Append("ŚśŜŝŞşŠšƧƨȘșȿʂϨϩЅѕᵴṠṡṢṣṤṥṦṧṨṩ$§".random());
                break;
                ...
            default:
                sb.Append(c);
                break;
        }
    }
    return sb.toString();
}
当然,剩下的字母也有类似的代码。最后一个字符串将显示在文本框中,可能还有其他各种控件。现在,我已经检查过了,我选择的所有字符都完全能够以我选择的字体显示在文本框中——我可以将它们复制/粘贴到文本框中,并且可以正常工作。但是当我运行这个程序时,字符串中会出现很多错误字符。我认为失败的地方在于我的
random
函数不理解字符串包含多字节字符。有没有什么方法可以修改它,使其符合要求

编辑:添加了肯定会产生故障的“s”集


编辑2:或者,如果有某种方法可以很容易地分辨出字符串中的哪些字符是多字节的,我可以删除它们,并从中选择较小的字符。很明显,我没有将字符用于它们的预期用途,因此为了简单起见,我可以牺牲一些多样性。

函数中没有错误。以下测试通过,它使用s字符串中的所有31个字母

public static class Extensions
{
    private static Random rand = new Random(1);

    public static char Random(this string str)
    {
        return str[rand.Next(str.Length)];
    }
}

[TestClass]
public class StackOverflow
{
    [TestMethod]
    public void MyTestMethod()
    {
        string s = "ŚśŜŝŞşŠšƧƨȘșȿʂϨϩЅѕᵴṠṡṢṣṤṥṦṧṨṩ$§";
        HashSet<char> expected = new HashSet<char>();
        HashSet<char> actual = new HashSet<char>();

        foreach (char c in s)
        {
            expected.Add(c);
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 1000; i++)
        {
            sb.Append(s.Random());
        }

        string str = sb.ToString();

        foreach (char c in str)
        {
            actual.Add(c);
        }

        Assert.AreEqual(1000, str.Length);
        CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList());
    }
}
公共静态类扩展
{
私有静态随机rand=新随机(1);
公共静态字符随机(此字符串str)
{
返回str[rand.Next(str.Length)];
}
}
[测试类]
公共类堆栈溢出
{
[测试方法]
公共void MyTestMethod()
{
字符串ᵴṠṡṢṣṤṥṦṧṨṩ$§";
HashSet预期值=新的HashSet();
HashSet实际值=新的HashSet();
foreach(字符c在s中)
{
增加(c);
}
StringBuilder sb=新的StringBuilder();
对于(int i=0;i<1000;i++)
{
某人附加(s.Random());
}
字符串str=sb.ToString();
foreach(str中的字符c)
{
增加(c);
}
断言。AreEqual(1000,str.Length);
CollectionAssert.AreEquivalent(预期为.ToList(),实际为.ToList());
}
}

问题可能出在另一个字母集中,而字符组合正是导致问题的原因。例如,我可以通过在字符串中包含一个组合变音符号,如\u0301,使@Harrison的测试用例失败。因此,如果没有看到其他集合和您正在使用的输入测试用例,很难说

忽略所有这些,如果您确实有组合字符或代理项对,那么正确的方法是使用迭代字符串逻辑字符。下面是一个性能不佳的示例,它将取代当前的随机实现

public static class Extensions
{
    private static Random rand = new Random(1);

    public static string Random(this string str)
    {
        var chars = new List<string>();
        var strElements = StringInfo.GetTextElementEnumerator(str);
        while (strElements.MoveNext())
        {
            chars.Add(strElements.GetTextElement());
        }
        return chars[rand.Next(chars.Count)];
    }
}
公共静态类扩展
{
私有静态随机rand=新随机(1);
公共静态字符串随机(此字符串str)
{
var chars=新列表();
var strElements=StringInfo.GetTextElementEnumerator(str);
while(strElements.MoveNext())
{
Add(strElements.GetTextElement());
}
返回字符[rand.Next(字符计数)];
}
}

这将涵盖所有情况,例如,字母
“ś”
可以通过其文字定义,长度为1,或者在长度为2的s
“s\u0301”
上使用组合字符。在渲染时,它们都表示相同的图示符。

为我们提供生成错误输出的示例输入。不是这样,字符串不包含多字节字符。这是8位编码的细节,.NET字符串以utf-16编码。你可能会弄错代理,但这是一个长距离拍摄,你的例子没有任何。在使用sb.ToString().ToCharArray()之后,请给出一个更好的输出错误示例。好的,可能是“a”很好,但我已经为所有26个字母列出了类似的列表,我认为这是太多重复代码,无法将其全部放在这里。我会尝试找到一个肯定失败的例子。(由于随机性,很难说是哪个字母引起了问题…)这就是为什么Random()需要种子。使其具有可预测的随机性。“我在字符串中出现了很多错误字符”,你这是什么意思。请给出一个“错误字符”的例子,说明你得到了什么以及你期望得到什么。这个函数对我来说似乎工作正常。你知道这是我第一次看到
CollectionAssert
我不确定到目前为止我的生活是怎样的。令人惊叹的!我会用数值迭代器通过字符串而不是
foreach
来测试这一点,因为它更接近于等价的(因为我是通过随机索引访问的)。这可能是因为在多字节字符中,两个字节都是单独添加的,所以虽然它们都在哈希集中,但它们自己无法正确显示。好吧,奇怪-我要发布的是,这在很多情况下仍然失败,但在植入随机生成器以获得可预测的输出后,它工作得非常好,然后继续工作,即使我移除了随机种子,所以我猜问题解决了?无论如何,性能不是问题,因为在加载过程中,这只在小输入上使用一次,所以我想说这是我的答案。