如何安全地拆分字符串?

4
当我们想要出于任何原因拆分字符串时,我们(至少是我)倾向于使用(管道)|字符进行拆分,因为很少会发现有人或应用程序在字符串上使用它...但是如果使用呢?
那么,简单的崩溃就会被抛出:)
我发现一个学院使用不可打印字符来执行相同的技术,例如:
String.Format(
         "{1}{0}{2}{0}{3}{0}{4}",
         (char)2,
         myFirstString,
         mySecondString,
         myThirdString,
         myFourthString);

当我们想要将整个字符串分解成其部分时

String.Split((char)2);

这种方法是否安全? 我应该采用这种方式来安全地拆分字符串吗? 还有其他的 安全技术吗?


没有上下文很难回答:不允许使用管道符号如何?在大多数情况下,这是合理的。 - Benjol
@Timwi,好的,让我重新表述一下:在大多数情况下,如果合理地将多个字符串“编码”为一个字符串,使用管道符应该就足够了。(例如,在Firefox中有多个主页) - Benjol
@Benjol,还是不行。唯一合理的情况是在字符串不包含管道符的情况下。管道字符在URL中是有效的。 - Timwi
6个回答

8
它可能比管道“更安全”,因为它更少见,但两种方式都不够优秀,因为它们限制了您可以使用的字符串子集。
考虑使用适当的编码——一种能明确地编码一组任意的字符串的编码。从编码角度来看,最简单的方法可能是仅对string[]进行序列化。您可以使用BinaryFormatterXmlSerializer或其他工具。
如果结果必须是一个字符串,并且它必须是一个字符串,那么您可以尝试这样做:
  • 编码:(将字符串列表转换为单个字符串)
    • !代替每个字符串中的!|代替每个字符串中的|。现在,没有一个字符串包含|,您可以轻松地将其反转。
    • 使用|作为分隔符连接这些字符串。
  • 解码:(将单个字符串还原为字符串列表)
    • |字符上拆分。
    • 在每个字符串中用!p替换|,用!替换!e。这可以恢复原始字符串。

1
如果原始字符串中有“!p”怎么办? - Grozz
@Grozz:这将被更改为!!p,并且仍然是无歧义的。但我现在看到,如果替换是分两个步骤而不是一个完成的话,就会出现错误,所以为了更容易实现,我将!!更改为!e。开心吗? - Timwi
在编程中,对于避免此问题,可以考虑使用 string[]BinaryFormatter。它们内置了一种处理该问题的结构。因此,在这方面使用它们会得到加分。 - Brian

3
这实质上是应用程序之间的合同,这些应用程序以此格式生成字符串,并由使用者消耗它们 - 在您的情况下使用适当的方式。您可能需要考虑是否有必要将多个字符串铺平成一个巨大的字符串。如果它们存在的唯一原因是表示应用程序内的“分离”文本数据,则最好从一开始就将数据作为字符串序列(例如string[])生成。在这种情况下,不需要进行“解析”。
另一方面,如果数据必须被持久化并在以后被消耗,有几个选项。例如:
1.数据库:将每个字符串存储为数据库表中的一行。无需拆分。
2.指定分隔符:使用“特殊”分隔符将字符串存储在扁平文件中,该分隔符表示当前字符串的结尾。显然,此字符必须不能是合法子字符串的一部分。例如,如果您的字符串不包含管道字符,那么这是一个合理的分隔符选择。
3.转义序列:例如,*是分隔符,**表示字符串的星号。这意味着没有字符被保留用于表示结束(使其不可表示)。但是,解析变成了一个非常重要的任务。
4.专门构建的格式:例如XML。当您考虑到这需要“转义”某些字符时,这本质上是点3的扩展,但现在问题已被推迟到您的XML库。

@John:为什么?因为它使用了很多流行语吗? - Timwi
@Timwi:感谢您的批评。您能告诉我哪些部分不清楚或使用了“手挥”流行语吗?这绝非本意,我希望能够清晰地传达含义。谢谢。 - Ani
@Ani:嘿嘿,如果我伤害了任何人的感情,对不起...你的回答没有问题,我的批评实际上是针对约翰的。 - Timwi
@Timwi:不要误会,显然,这位提问者有一个值得真正讨论的真正问题,我不想在一个真正的问题上仅仅使用流行语来解决它。这就是为什么我提出了这个问题。 - Ani
@Timwi,我这里没有看到任何流行语,只有一个清晰和合理的答案。也许我是一位CIO,只是还不知道而已。 - John M Gant
@Timwi,顺便说一句,我也给你的回答点了赞,即使没有流行语词汇,就在我给Ani点赞之后。我认为你们两个都提出了很好的观点。 - John M Gant

2

如果可以的话,最好不要在第一时间将字符串连接起来。像这样分割字符串是代码的味道。

当然,使用控制字符“更有可能”不会出现问题,但它仍然不完美。如果您真的必须这样做,请使用NUL (\0)。该字符至少具有作为字符串标记的历史。


2

我认为使用不可打印字符比安全更加隐晦。 如果你想要安全,一个解决方案是将你的List<string>序列化/反序列化。


1

0

这取决于字符串的预期内容。如果预期的字符串可能包含非可打印字符,则可能不行。另一种方法是转义要拆分的字符串,这看起来更费力,但可以放入可重用的帮助程序中:

var string1 = "string|1";
var string2 = "string |2";
var string3 = "string| 3";
var string4 = "string | 4";

var stringToSplit = MergeStrings(string1, string2, string3, string4);

var results = SplitString( stringToSplit );

foreach(string result in results)
{
    Trace.WriteLine( result );
}

使用以下方法。

public string MergeStrings(params string[] strings)
{
    var stringBuilder = new StringBuilder();

    foreach(var s in strings)
    {
        stringBuilder.Append( s.Replace( "|", "||" ) );
        stringBuilder.Append( " | " );
    }

    return stringBuilder.ToString();
}

public IEnumerable<string> SplitString(string stringToSplit)
{
    var results = stringToSplit.Split( new[] { " | " }, StringSplitOptions.RemoveEmptyEntries );

    return results.Select( result => result.Replace( "||", "|" ) );
}

你可能想要使分隔符可定制化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接