如何拆分可能包含分隔符的用户生成的字符串?

时间:2009-09-19 16:47:39

标签: c# csv delimited-text

我想使用逗号作为分隔符来String.Split()以下字符串:

John,Smith,123 Main Street,212-555-1212

以上内容由用户输入。如果他们在地址中输入逗号,则生成的字符串会导致String.Split()出现问题,因为您现在有5个字段而不是4个字段:

John,Smith,123 Main Street, Apt 101,212-555-1212

我可以在所有用户输入上使用String.Replace()来用其他东西替换逗号,然后再次使用String.Replace()将东西转换回逗号:

value = value.Replace(",", "*");  

但是,如果用户碰巧在其输入中使用占位符分隔符“*”,则仍然会被愚弄。那么你最终会得到额外的逗号而且结果中没有星号。

我在网上看到了处理转义分隔符的解决方案,但我还没有找到解决这种看似常见情况的解决方案。我错过了什么?

编辑:这称为delimitter collision

9 个答案:

答案 0 :(得分:4)

这是一个常见的场景 - 你有一些任意的字符串值你想要组成一个结构,它本身就是一个字符串,但不允许这些值干扰它们周围结构的分隔符。

您有几种选择:

  1. 输入限制:如果您的方案可以接受,最简单的解决方案是限制在值中使用分隔符。在您的具体情况下,这意味着禁止使用逗号。
  2. 编码:如果输入限制不合适,下一个最简单的选项是对整个输入值进行编码。选择在其可能输出范围内没有分隔符的编码(例如,Base64在其编码输出中不包含逗号)
  3. 转义分隔符:稍微复杂的选项是提出转义分隔符的约定。如果你正在使用像CSV这样的主流产品,很可能已经解决了转义问题,而且你可以使用一个标准的库。如果没有,那么需要考虑一个完整的转义系统,并实施它。
  4. 如果您可以灵活地不使用CSV进行数据表示,则会打开许多​​其他选项。 (例如,考虑参数化SQL查询通过将参数值与查询字符串分开存储来回避输入转义的复杂性的方式。)

答案 1 :(得分:3)

这对你来说可能不是一个选项,但是使用一个非常罕见的字符(例如一个管道)作为你的分隔符并且不允许在第一个实例中输入这个字符会更容易吗?

答案 2 :(得分:3)

如果这是CSV,则地址应该用引号括起来。广泛使用CSV解析器,在解析文本时将其考虑在内。

John,Smith,"123 Main Street, Apt. 6",212-555-1212

答案 3 :(得分:2)

一个万无一失的解决方案是将用户输入转换为base64,然后用逗号分隔。这意味着您必须在解析后转换回来。

答案 4 :(得分:0)

您可以尝试在每个用户输入周围加上引号或其他一些开始和结束分隔符,并忽略一组引号之间的任何特殊字符。

这实际上归结为清理用户输入的情况。您应该只允许用户输入中的所需字符,并拒绝/删除用户的无效输入。这样您就可以使用星号分隔符。

最好的解决方案是定义有效字符,并以某种方式拒绝无效字符,然后使用无效字符(因为它们被“禁止”而不会出现在输入中)作为分隔符

答案 5 :(得分:0)

不允许用户输入您用作分隔符的字符。我个人觉得这是最好的方式。

答案 6 :(得分:0)

有趣的解决方案(如果地址是唯一具有昏迷的字段,则有效):

用昏迷分割字符串。名字和姓氏前两件;最后一块是电话 - 带走那些。通过昏迷将其余部分合并 - 这将是地址;)

答案 7 :(得分:0)

从某种意义上说,用户已经“使用空格”转义“逗号”。

所以,试试这个:

string[] values = RegEx.Split(value, ",(?![ ])");

如果用户没有放置空格,用户仍然可以解除此问题,并且有一种更加万无一失的方法(使用引用包含逗号的值的标准CSV方法),但这样做可以解决用例你的问题已经提出了。

还有一个解决方案:提供一个“地址2”字段,这是传统上公寓号码之类的东西。如果用户懒惰,用户仍然可以破解它,但是在地址2之后他们实际上会破坏字段。

答案 8 :(得分:-1)

礼貌地提醒您的用户,美国和加拿大正确形成的街道地址不应该包含任何标点符号,或许?

在没有启发式逻辑的情况下,将损坏的数据自动转换为有用数据的过程非常重要。您可以尝试通过调用第三方地址格式化库来外包解析,以应用USPS格式规则。

即使USPS要求用户执行大部分工作,方法是将地址的组件输入到地址“canonicalizer”页面(http://zip4.usps.com/zip4/welcome.jsp)的不同字段中。