用于分隔字符串的逗号分隔符是什么?

我有几个文本框,用户可以在其中输入信息。 这可以包括逗号,所以我不能使用标准的逗号分隔字符串。

什么是一个好的分隔符来表示应该根据用户在其着作中通常不使用的字符来分隔字符串? 我将把这些字段组合成一个字符串字符串并将它们传递给我的加密方法。 解密后我需要能够可靠地分离它们。

如果重要的话,我正在使用C#。

| 将列在我的列表中,通常用作CSV的替代品。 google“pipe delimited”,你会发现很多例子。

string[] items = new string[] {"Uno","Dos","Tres"}; string toEncrypt = String.Join("|", items); items = toEncrypt.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries); foreach(string s in items) Console.WriteLine(s); 

因为每个人都喜欢成为编码的批评者并且不提供代码,所以这里有一种方法来编码文本,所以你的| delim不会碰撞。

 string[] items = new string[] {"Uno","Dos","Tres"}; for (int i = 0; i < items.Length; i++) items[i] = Convert.ToBase64String(Encoding.UTF8.GetBytes(items[i])); string toEncrypt = String.Join("|", items); items = toEncrypt.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries); foreach (string s in items) Console.WriteLine(Encoding.UTF8.GetString(Convert.FromBase64String(s))); 

我已经看到exception字符被用作分隔符,甚至像-|::|-这样的exception字符组合,但是尽管它们更不可能发生,但它们仍然可以。

如果你想让它保持水密,你基本上有两种选择:

1:使用无法输入的字符,例如’\ 0’字符:

加入:

 string combined = string.Join("\0", inputArray); 

分裂:

 string[] result = combined.Split('\0'); 

2:转义字符串并使用转义字符作为分隔符,如url编码值并使用&作为分隔符:

加入:

 string combined = string.Join("&", inputArray.Select(System.Web.HttpUtility.UrlEncode).ToArray()); 

分裂:

 string[] result = combined.Split('&').Select(System.Web.HttpUtility.UrlDecode).ToArray(); 

最好的解决方案是坚持使用逗号并引入对字符转义的支持。 无论您选择哪种角色最终都需要输入,因此您也可以为此提供支持。

在双引号字符串中思考反向语言+双引号。

不要选择像反引号这样的字符,因为有些用户可能不知道如何键入它…

自从我停止使用C以来,我不认为自己已经自愿划分了一系列字符串。没有必要使用“现代”语言,并且 – 虽然微不足道 – 边缘情况的数量足以惹恼你致死

将它们存储在List 或string []中,并对它们进行序列化/反序列化。 如果您想要人类可读性或互操作,请使用XML – 如果不需要,则使用二进制序列化。 您可以轻松地加密输出,并且没有歧义或创建您自己的转义例程。

在C#中,它的LOC较少,写入时间比这个答案要少。 没有理由推出自己的解决方案。

任何非标准字符管|,反引号`,波浪号〜,爆炸!或分号; 可能会奏效。 但是,如果你走这条路,你真的冒险离开了可用性。 要求他们用反斜杠或其他东西来逃避逗号,请求他们错过一个。

如果无法使用CSV,则应考虑更改UI。 (哎呀,无论如何,你应该远离CSV用户输入!)你说文本框所以我假设你在网络或某种获胜forms或WPF(绝对不是控制台)。 所有这些都为您提供了比单个文本框更好的UI控件,并迫使用户遵循您难以实现的UI设计。

更多信息肯定有助于更好地指导答案。

但是,作为使用反斜杠转义逗号的示例。 请注意,在使用逗号之前,您无法转义反斜杠。 所以@“uno,dos,tr \\,es”将以{“uno”,“dos”,“tr \ es”}结束。

 string data = @"uno, dos, tr\,es"; string[] items = data.Split(','); // {"uno", " dos", @"tr\", "es"} List realitems = new List(); for (int i=items.Length-1; i >= 0; i--) { string item = items[i]; if (item.Length == 0) { realitems.Insert(0, ""); continue; } if (realitems.Count == 0) { realitems.Insert(0, item); } else { if (item[item.Length - 1] == '\\') { realitems[0] = item + "," + realitems[0]; } else { realitems.Insert(0, item); } } } // Should end up with {"uno", " dos", "tr,es"} 

用户是否会在文本框中输入分隔的字符串,还是会输入单独的字符串,然后由代码将其构建为分隔的字符串?

在第一种情况下,重新考虑您的UI可能更好。 例如,用户可以一次输入一个字符串到文本框中,然后在每个字符串后单击“添加到列表”按钮。

在第二种情况下,使用哪个分隔符并不重要。 选择您喜欢的任何角色,只需确保您逃脱该角色的任何其他出现。

编辑

由于对其他答案的几条评论都要求代码,这里有一个创建逗号分隔字符串的方法,使用反斜杠作为转义字符:

 public static string CreateDelimitedString(IEnumerable items) { StringBuilder sb = new StringBuilder(); foreach (string item in items) { sb.Append(item.Replace("\\", "\\\\").Replace(",", "\\,")); sb.Append(","); } return (sb.Length > 0) ? sb.ToString(0, sb.Length - 1) : string.Empty; } 

这是将逗号分隔的字符串转换回单个字符串集合的方法:

 public static IEnumerable GetItemsFromDelimitedString(string s) { bool escaped = false; StringBuilder sb = new StringBuilder(); foreach (char c in s) { if ((c == '\\') && !escaped) { escaped = true; } else if ((c == ',') && !escaped) { yield return sb.ToString(); sb.Remove(0, sb.Length); } else { sb.Append(c); escaped = false; } } yield return sb.ToString(); } 

以下是一些示例用法:

 string[] test = { "no commas or backslashes", "just one, comma", @"a comma, and a\ backslash", @"lots, of\ commas,\ and\, backslashes", @"even\\ more,, commas\\ and,, backslashes" }; string delimited = CreateDelimitedString(test); Console.WriteLine(delimited); foreach (string item in GetItemsFromDelimitedString(delimited)) { Console.WriteLine(item); } 

我想最终,每个角色都会被某人使用。 用户总能找到一种方法来打破我们的HL7解析器。

而不是单个字符,也许尝试一个随机的字符串,没有人会使用它。 就像是 ”#!@!#”。

我假设您说的是用户将数据输入到单独的字段中,然后您将它组合在一起。 因此用户永远不需要知道或关心分隔符是什么。

不要只是尝试选择一个“没人用过”的角色,因为无论是偶然还是为了试图破坏你的代码,一些用户最终都会使用它。

所以,我要么:

  • 插入反斜杠以在用户输入中转义逗号和反斜杠,然后将字符串与逗号组合。 要分离,您可以拆分未转义的逗号(这是状态机的工作),然后对每个组件进行转换。

  • 使用现成的序列化字符串列表的方法。 什么是可用的取决于您的环境,我不知道C#/。NET足够建议。 在Java中,您可以序列化一个向量或其他任何东西。

  • 使用ASCII-BEL或ASCII-VT等控制字符(或者如果您的字符串永远不会被视为以空字符结尾的ASCII-NUL)分隔数据,并拒绝包含该字符的用户输入。

如果必须允许用户输入他们喜欢的任何char值,则第一个选项是好的。 如果您不关心数据膨胀,第二种选择是好的。 如果您不介意拒绝尝试插入有趣数据的smart-alec用户(或那些有不寻常要求的用户),那么第三种选择是好的。

如前所述,您选择的任何字符都有可能出现在输入中,因此您必须处理转义。 XML可能是一种很好的序列化格式,因为我相信.NET具有良好的XML创建和删除支持。 这可能比尝试实现自己的字符转义要强大得多,并且将来也会更加可扩展。

没人说TAB? 制表符分隔很好但是在GUI中键入制表符并不容易(它往往会将您移动到下一个屏幕元素)。 但是对于由计算机生成的文件,TAB是完美的,因为它真的不应该出现在用户生成的文本中。

为什么不用引号括起每个输入?

那样你最终得到这个:

 "Aaron","Johnson","25","I like cats, and dogs" 

不要忘记输入引号中的引号…

马克布拉克特有正确的答案。 我只想补充说,这个简单问题的答案数量应该会让你不再使用分隔字符串。 让这成为“明智的话语”。

反击。 没有人使用反击。

管道字符(|),也许? 如果您的用户群非常狡猾,那么这种方法(要求他们划分文本)可能不是最好的方法; 你可以尝试别的东西,例如提供一些动态添加文本框的方法,它接受另一个字符串等。

如果您提供有关您正在做什么以及为谁做的更多信息,则可能有人建议替代方法。

新队? (即使用多行文本框)

我建议使用“;”

我更喜欢使用不太可能由普通人输入的字符组合作为我的分隔符。 例如,我使用了“)^&^(”并在我的代码中将其设置为const“cDelimiter”;然后将我的所有字段连接起来。通过使用一个小的唯一字符串,我大大减少了可能的引擎盖用户不小心进入我的分隔符。用户输入一个或一个〜的可能引擎不太可能,但这并不意味着它不会发生。

检测未使用的字符,然后使用它。 您的最终组合字符串可以从用作分隔符的那一点开始。

例如:您的用户输入“pants”“,;,;,;,;,;” 和“| ~~ |” 迭代一组字符,直到找到一个未使用的字符。 可能是,比方说,“$”你最后的串联字符串是“$ pants $,;,;,;,;,; $ | ~~ |” 初始字符告诉您的程序将哪个字符用作分隔符。 这样,没有禁止的字符,句号。

使用选项卡(或可能是\ n) – 如果用户输入将导致退出文本框。

我也支持选择TAB(\ t)和扩展PIPE(|)符号。

但是在我的经验中最常用的是分号(;)以及引用的字段和\和\的转义,这是完美的。只需要一个解析器保持状态。实际的分隔字符变得不重要。

如果你不使用转义,那么计算每行的“字段”并将它们与预期结果进行比较是明智的。 由于此类文件的大多数应用程序使用某种固定数量的字段,您可以捕获条目中的错误,如果它不触发,一切都是好的感觉。

我知道这个反应已经很晚了,但我一段时间后就遇到了这个问题并且相当好地解决了这个问题(恕我直言)。 希望将来,这将有助于其他人寻找类似问题的答案。

虽然我一般会把自己置于类似于Mike Ottum,John Saunders和Mark Brackett的阵营中,但问题的简单事实是,有时我们的开发人员必须做我们不愿意做的事情。 我的特殊情况需要提供一个(大部分)人类可读的“id”来在RESTful URI中使用,该RESTful URI是从对象的有机复合键派生的。 二进制或XML序列化不是一个真正的选择。 所以? 我选择尽可能少地重新发明轮子。 System.Text.RegularExpressions.Regex类具有对这些疯狂的正则表达式模式进行操作的escape / unescape方法。 有一些可以逃脱的角色可供选择。 我选择了管道(’|’)字符。

这是我的实现(类似于重用,但你可以为7行“内联”解决方案划出好的位,如果这是你想要滚动的方式):

 using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace RPlus.DTO { ///  /// Provide safe string un/concatenating ///  static class Glob { // a Regex Split param that basically says: // Split on the pipe char unless the preceeding char is a backslash private const string _splitterer = @"(? /// Produce a properly escaped concatenation /// from some number of strings ///  /// strings to escape/concate /// an escaped concatenation of items public static string To(IEnumerable items) { var escapedItems = new List(); foreach (var s in items) escapedItems.Add(Regex.Escape(s)); return string.Join(_delimiter.ToString(), escapedItems); } ///  /// Unconcatenate/unescape a string into its original strings ///  ///  /// A value returned from Glob.To() ///  ///  /// The orignal strings used to construct the globbedValue ///  public static List From(string globbedValue) { return From(globbedValue, default(int?)); } ///  /// Unconcatenate/unescape a string into its original strings ///  ///  /// A value returned from Glob.To() ///  ///  /// The number of string tokens that /// should be found in the concatenation ///  ///  /// The orignal strings used to construct the globbedValue ///  public static List From(string value, int? expectedTokens) { var nugs = Regex.Split(value, _splitterer); if (expectedTokens.HasValue && nugs.Length != expectedTokens.Value) throw new ArgumentException("Unexpected number of tokens"); var unescapedItems = new List(); foreach (var s in nugs) unescapedItems.Add(Regex.Unescape(s)); return unescapedItems; } } } 

以下是一些示例用法:

 var glob = Glob.To(new string[] { "Foo|Bar", "Bar|Baz", "Baz|Qux" }); var orig = Glob.From(glob); 

CAVEAT:请不要试图找到“用户不会输入的字符”作为连接字符串的分隔符。 用户最终会输入它。 已经有足够的“神奇数字”代码等待爆炸。 并且有许多经过试验和测试的解决方案。