[英]Removing all whitespace lines from a multi-line string efficiently
在C#中,删除空行的最佳方法是什么,即只包含字符串空格的行? 如果这是最好的解决方案,我很高兴使用正则表达式。
编辑:我应该添加我使用.NET 2.0。
赏金更新 :奖励之后我会回滚,但我想澄清一些事情。
首先,任何Perl 5 compat正则表达式都可以。 这不仅限于.NET开发人员。 标题和标签已经过编辑以反映这一点。
其次,虽然我在赏金细节中给出了一个简单的例子,但它并不是你必须满足的唯一测试。 您的解决方案必须删除除空格以外的所有行, 以及最后一行换行符 。 如果有一个字符串,在运行正则表达式后,以“/ r / n”或任何空白字符结尾,则会失败。
如果要删除包含任何空格(制表符,空格)的行,请尝试:
string fix = Regex.Replace(original, @"^\s*$\n", string.Empty, RegexOptions.Multiline);
编辑(对于@Will):修剪尾随换行符的最简单方法是在结果字符串上使用TrimEnd
,例如:
string fix =
Regex.Replace(original, @"^\s*$\n", string.Empty, RegexOptions.Multiline)
.TrimEnd();
string outputString;
using (StringReader reader = new StringReader(originalString)
using (StringWriter writer = new StringWriter())
{
string line;
while((line = reader.ReadLine()) != null)
{
if (line.Trim().Length > 0)
writer.WriteLine(line);
}
outputString = writer.ToString();
}
脱离我的头顶......
string fixed = Regex.Replace(input, "\s*(\n)","$1");
转过来:
fdasdf asdf [tabs] [spaces] asdf
进入这个:
fdasdf asdf asdf
使用LINQ:
var result = string.Join("\r\n",
multilineString.Split(new string[] { "\r\n" }, ...None)
.Where(s => !string.IsNullOrWhitespace(s)));
如果您正在处理大输入和/或不一致的行结尾,则应使用StringReader并使用foreach循环执行上述old-school。
不好。 我会使用JSON.net使用这个:
var o = JsonConvert.DeserializeObject(prettyJson);
new minifiedJson = JsonConvert.SerializeObject(o, Formatting.None);
好的,这个答案符合赏金中规定的明确要求:
我还需要删除任何尾随换行符,我的正则表达式失败了。 我的赏金给任何能给我一个通过这个测试的正则表达式的人:StripWhitespace(“test \\ r \\ n \\ r \\ n \\ n \\ n \\ r \\ n \\ n \\ r \\ n”)==“test \\ r \\ nthis”
所以这是答案:
(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|(\r?\n)+\z
或者@Chris Schmich提供的C#代码:
string fix = Regex.Replace("test\r\n \r\nthis\r\n\r\n", @"(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|(\r?\n)+\z", string.Empty, RegexOptions.Multiline);
现在让我们试着理解它。 这里有三个可选模式,我愿意用string.empty
替换。
(?<=\\r?\\n)(\\s*$\\r?\\n)+
- 将一个匹配为仅包含空格并且前面有换行符的无限行(但与第一个前一个换行符不匹配)。 (?<=\\r?\\n)(\\r?\\n)+
- 将一行与无限空行匹配,其中没有内容以换行符为前缀(但与前一行换行符不匹配)。 (\\r?\\n)+\\z
- 在测试字符串的末尾匹配一个到无限制的换行符(在调用它们时跟踪换行符) 这完全满足您的测试! 但也满足\\r\\n
和\\n
换行样式! 测试出来! 我相信这将是最正确的答案,虽然更简单的表达式将通过您指定的赏金测试,这个正则表达式传递更复杂的条件。
编辑: @Will指出上述正则表达式的最后一个模式匹配中的潜在缺陷,因为它不会匹配测试字符串末尾包含空格的多个换行符。 那么让我们改变最后一个模式:
\\b\\s+\\z
\\ b是单词边界(单词的开头或结尾),\\ s +是一个或多个空格字符,\\ z是测试字符串的结尾(“文件”的结尾) 。 所以现在它将匹配文件末尾的任何分类的空格,包括选项卡和空格以及回车和换行符。 我测试了@Will提供的两个测试用例。
所以现在一起,它应该是:
(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|\b\s+\z
编辑#2:好的还有一个可能的案例@Wil发现最后一个正则表达式没有涵盖。 这种情况是在任何内容之前在文件开头有换行符的输入。 因此,我们再添加一个模式以匹配文件的开头。
\\A\\s+
- \\A
匹配文件的开头, \\s+
匹配一个或多个空格字符。
所以现在我们有了:
\A\s+|(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|\b\s+\z
所以现在我们有四种匹配模式:
\\r\\n \\r\\n\\t\\r\\n
) \\r\\n\\r\\n
) 为了回应Will的赏金,它希望解决方案采用"test\\r\\n \\r\\nthis\\r\\n\\r\\n"
并输出"test\\r\\nthis"
,我想出了一个解决方案,利用原子分组 (在MSDN上称为Nonbacktracking Subexpressions )。 我建议阅读这些文章,以便更好地了解正在发生的事情。 最终,原子组帮助匹配原本留下的后续换行符。
使用此模式使用RegexOptions.Multiline
:
^\s+(?!\B)|\s*(?>[\r\n]+)$
这是一个包含一些测试用例的例子,包括我从Will对其他帖子的评论以及我自己的评论中收集到的一些测试用例。
string[] inputs =
{
"one\r\n \r\ntwo\r\n\t\r\n \r\n",
"test\r\n \r\nthis\r\n\r\n",
"\r\n\r\ntest!",
"\r\ntest\r\n ! test",
"\r\ntest \r\n ! "
};
string[] outputs =
{
"one\r\ntwo",
"test\r\nthis",
"test!",
"test\r\n ! test",
"test \r\n ! "
};
string pattern = @"^\s+(?!\B)|\s*(?>[\r\n]+)$";
for (int i = 0; i < inputs.Length; i++)
{
string result = Regex.Replace(inputs[i], pattern, "",
RegexOptions.Multiline);
Console.WriteLine(result == outputs[i]);
}
编辑:为了解决模式无法用空白和换行符混合清理文本的问题,我将\\s*
添加到正则表达式的最后一个交替部分。 我之前的模式是多余的,我意识到\\s*
会处理这两种情况。
如果只有White空格,为什么不使用C#字符串方法
string yourstring = "A O P V 1.5";
yourstring.Replace(" ", string.empty);
结果将是“AOPV1.5”
string corrected =
System.Text.RegularExpressions.Regex.Replace(input, @"\n+", "\n");
这是另一个选择:使用StringReader
类。 优点:一次遍历字符串,不创建中间数组。
public static string RemoveEmptyLines(this string text) {
var builder = new StringBuilder();
using (var reader = new StringReader(text)) {
while (reader.Peek() != -1) {
string line = reader.ReadLine();
if (!string.IsNullOrWhiteSpace(line))
builder.AppendLine(line);
}
}
return builder.ToString();
}
注意: IsNullOrWhiteSpace
方法是.NET 4.0中的新增功能 。 如果你没有这个,那么自己写一点是微不足道的:
public static bool IsNullOrWhiteSpace(string text) {
return string.IsNullOrEmpty(text) || text.Trim().Length < 1;
}
我会去:
public static string RemoveEmptyLines(string value) {
using (StringReader reader = new StringReader(yourstring)) {
StringBuilder builder = new StringBuilder();
string line;
while ((line = reader.ReadLine()) != null) {
if (line.Trim().Length > 0)
builder.AppendLine(line);
}
return builder.ToString();
}
}
为了回应Will的赏金,这里有一个Perl sub,可以对测试用例给出正确的响应:
sub StripWhitespace {
my $str = shift;
print "'",$str,"'\n";
$str =~ s/(?:\R+\s+(\R)+)|(?:()\R+)$/$1/g;
print "'",$str,"'\n";
return $str;
}
StripWhitespace("test\r\n \r\nthis\r\n\r\n");
输出:
'test
this
'
'test
this'
为了不使用\\R
,将其替换为[\\r\\n]
并反转替代。 这个产生相同的结果:
$str =~ s/(?:(\S)[\r\n]+)|(?:[\r\n]+\s+([\r\n])+)/$1/g;
不需要特殊配置和多线路支持。 不过你可以添加s
标志,如果它是强制性的。
$str =~ s/(?:(\S)[\r\n]+)|(?:[\r\n]+\s+([\r\n])+)/$1/sg;
字符串扩展
public static string UnPrettyJson(this string s)
{
try
{
// var jsonObj = Json.Decode(s);
// var sObject = Json.Encode(value); dont work well with array of strings c:['a','b','c']
object jsonObj = JsonConvert.DeserializeObject(s);
return JsonConvert.SerializeObject(jsonObj, Formatting.None);
}
catch (Exception e)
{
throw new Exception(
s + " Is Not a valid JSON ! (please validate it in http://www.jsoneditoronline.org )", e);
}
}
char[] delimiters = new char[] { '\r', '\n' };
string[] lines = value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
string result = string.Join(Environment.NewLine, lines)
我不确定它是否有效但=)
List<string> strList = myString.Split(new string[] { "\n" }, StringSplitOptions.None).ToList<string>();
myString = string.Join("\n", strList.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList());
如果针对每条线路工作,这是一件简单的事......
(^\s+|\s+|^)$
呃。 好吧,经过这一切,我找不到一个可以击中我能想到的所有角落情况。 以下是我最新的正则表达式
(<=(\\ r \\ n)的|?^)\\ S * \\ r \\ n | \\ r \\ n \\ S * $
基本上说:
前半部分捕获字符串开头的所有空格,直到第一个非空白行,或非空白行之间的所有空格。 下半部分阻塞了字符串中剩余的空格,包括最后一个非空白行的换行符。
感谢所有试图帮助的人; 你的答案帮助我思考了匹配时需要考虑的一切。
*(此正则表达式认为换行符为\\r\\n
,因此必须根据字符串的来源进行调整。不需要设置选项以运行匹配。)
试试这个。
string s = "Test1" + Environment.NewLine + Environment.NewLine + "Test 2";
Console.WriteLine(s);
string result = s.Replace(Environment.NewLine, String.Empty);
Console.WriteLine(result);
s = Regex.Replace(s, @"^[^\n\S]*\n", "");
[^\\n\\S]
匹配任何不是换行符或非空白字符的字符 - 因此,除了\\n
之外的任何空格字符。 但很可能你唯一需要担心的字符是空格,制表符和回车符,所以这也应该有效:
s = Regex.Replace(s, @"^[ \t\r]*\n", "");
如果你想让它赶上最后一行,没有最后的换行符:
s = Regex.Replace(s, @"^[ \t\r]*\n?", "");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.