从字符串中删除字符

Posted

技术标签:

【中文标题】从字符串中删除字符【英文标题】:Delete character out of string 【发布时间】:2016-07-26 14:45:27 【问题描述】:

我在完成一项非常简单的任务时遇到了一些问题 - 我觉得我在这里遗漏了一些非常明显的东西。

我有一个分号分隔的 .csv 文件。在这个文件中有几个包含点的数字,比如“1.300”,但也有一些日期,比如“2015.12.01”。任务是查找并删除所有点,但只删除那些以数字表示且不是以日期表示的点。日期和数字是完全可变的,并且不会在文件中的相同位置。

我现在的问题是:处理这个问题的“最佳”方法是什么?

程序员的角度来看:在每个半分符处拆分,计算点数,如果只有一个点,删除它是一个好的解决方案吗?这是解决我现在能想到的问题的唯一方法。


示例源文件:

2015.12.01;
13.100;
500;
1.200;
100;

示例结果:

2015.12.01;
13100;
500;
1200;
100;

【问题讨论】:

文件中能否有不同的日期格式,例如 YYYY.MM(没有天数)? 听起来你很可能想要一个正则表达式... 这不是删除字符,这是解析文本。这不是一件容易的事。顺便说一句为什么删除点?它们是完全有效的分隔符。您是否有不同的问题,例如尝试使用错误的文化解析数字? 这可能是一个有效的问题@Pan 如果大型导出出错并且该文件只剩下您了。 @Lunatiic 为什么?如果您使用奥地利语言环境(只是使用. 进行分组和日期分隔符的国家之一),您可以使用decimal.Parse("13.100",new System.Globalization.CultureInfo("de-at")) 解析数字并获得13100 【参考方案1】:

如果您可以依赖日期有两个点和数字只有一个这一事实,则可以将其用作过滤器:

string s = "123.45";
if (s.Count(x => x == '.') == 1)

    s = s.Replace(".", null);

【讨论】:

为了提高性能,最好在计算点数之前检查行长(假设格式保持不变,带日期的行应该正好是 12 个字符)。跨度> 好点@Fabjan。在这方面有很多可能的改进。 午饭后我要试试你的解决方案。提前感谢@Fabjan 日期格式始终保持 yyyy.mm.dd【参考方案2】:

我不会依赖点的数量,因为可能会出错。

您可以使用double.TryParse 安全地测试字符串是否为数字

var data = "2015.12.01;13.100;500;1.200;100;";

var dataArray = data.Split(';');

foreach (var s in dataArray)

    double result;
    if(double.TryParse(s,out result))
        // implement your logic here
        Console.WriteLine(s.Replace(".",string.Empty));

【讨论】:

这很可能会引入错误。 13.100 可以是 13100 或 13.100,具体取决于文化。 TryParse 永远不会失败,只是返回不同的结果【参考方案3】:

源文件看起来像是由运行在机器上的程序生成的有效文件,该机器的语言环境使用. 作为千位分隔符(欧洲大部分地区使用)和日期分隔符(我认为只有德国语言环境)。这样的语言环境也使用; 作为列表分隔符。

如果问题只是如何解析这些日期、数字,答案是将正确的文化传递给解析函数,例如:decimal.Parse("13.500",new CultureInfo("de-at")) 将返回 13500。但实际问题是必须提供数据到另一个使用. 作为小数分隔符的程序。

最安全的选择是更改导出程序使用的语言环境,例如,如果导出程序是 .NET 程序,则将线程 CultureInfo、SSIS 包中的语言环境等更改为en-gb 之类的语言环境以用于导出. 并避免奇怪的日期格式。这假设管道中的下一个程序不使用德语作为日期,使用英语作为数字

另一个选项是加载文本,使用适当的语言环境解析字段,然后以下一个程序所需的格式导出它们。

最后,正则表达式可用于仅匹配数字字段并删除点。这可能有点棘手,取决于实际内容。

例如(\d+)\.(\d3) 可用于匹配数字,如果只有一千位分隔符。如果某些文本字段包含相似的值,这可能会失败。或者;(\d+)\.(\d3); 只能匹配一个完整的字段,除了第一个和最后一个字段,例如:

Regex.Replace("1.457;2016.12.30;13.000;1,50;2015.12.04;13.456",@";(\d+)\.(\d3);",@"$1$2;")

产生:

1.457;2016.12.3013000;1,50;2015.12.04;13.456

匹配; 之间的数字或第一个/最后一个字段的正则表达式可以是

 (^|;)(\d+)\.(\d3)(;|$)

这将产生1457;2016.12.30;13000;1,50;2015.12.04;13456,例如:

var data="1.457;2016.12.30;13.000;1,50;2015.12.04;13.456";

var pattern=@"(^|;)(\d+)\.(\d3)(;|$)";
var replacement=@"$1$2$3$4";

var result= Regex.Replace(data,pattern,replacement);

与拆分和替换字符串相比,正则表达式的优势在于它很多速度更快,内存效率更高。 Regex 不会为每个拆分、操作生成临时字符串,而是仅计算源中的索引。 在您请求最终文本结果时生成字符串对象。这会大大减少分配和垃圾回收。

即使在中等大小的文件中,这也可以使性能提高 10 倍

【讨论】:

以上是关于从字符串中删除字符的主要内容,如果未能解决你的问题,请参考以下文章

从字符串中删除字符

从R中的字符串中删除所有特殊字符?

使用javascript从字符串中删除字符

从字符串中删除多个子字符串 - Java

从字符串中删除前面的字符?

从字符串中删除字符直到另一个字符出现[关闭]