简单易懂:
string streamR = sr.ReadLine(); // sr.Readline results in:
// one "two two"
我希望能够将它们保存为两个不同的字符串,删除所有空格除了引号之间的空格。因此,我需要的是:
string 1 = one
string 2 = two two
到目前为止,我发现有效的是以下代码,但它删除了引号中的空格。
//streamR.ReadLine only has two strings
string[] splitter = streamR.Split(' ');
str1 = splitter[0];
// Only set str2 if the length is >1
str2 = splitter.Length > 1 ? splitter[1] : string.Empty;
此输出变为
one
two
我已经调查了Regular Expression to split on spaces unless in quotes但是我似乎无法让正则表达式来工作/理解代码,特别是如何分割它们以便它们是两个不同的字符串。那里的所有代码都给我一个编译错误(我正在使用System.Text.RegularExpressions
)
答案 0 :(得分:50)
string input = "one \"two two\" three \"four four\" five six";
var parts = Regex.Matches(input, @"[\""].+?[\""]|[^ ]+")
.Cast<Match>()
.Select(m => m.Value)
.ToList();
答案 1 :(得分:30)
你甚至可以在没有正则表达式的情况下做到这一点:带String.Split
的LINQ表达式可以完成这项工作。
您可以在"
之前拆分字符串,然后在结果数组中仅按拆分偶数索引的元素。
var result = myString.Split('"')
.Select((element, index) => index % 2 == 0 // If even index
? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) // Split the item
: new string[] { element }) // Keep the entire item
.SelectMany(element => element).ToList();
对于字符串:
This is a test for "Splitting a string" that has white spaces, unless they are "enclosed within quotes"
它给出了结果:
This
is
a
test
for
Splitting a string
that
has
white
spaces,
unless
they
are
enclosed within quotes
string myString = "WordOne \"Word Two\"";
var result = myString.Split('"')
.Select((element, index) => index % 2 == 0 // If even index
? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) // Split the item
: new string[] { element }) // Keep the entire item
.SelectMany(element => element).ToList();
Console.WriteLine(result[0]);
Console.WriteLine(result[1]);
Console.ReadKey();
如何定义字符串的引用部分?
我们假设第一个"
之前的字符串没有引用。
然后,引用位于第一个"
之间和第二个"
之间的字符串。第二个"
和第三个"
之间的字符串未引用。引用第三个和第四个之间的字符串,......
一般规则是:引用第(2 * n-1)th(奇数)"
和第(2 * n)th(偶数)"
之间的每个字符串。 (1)
与String.Split
的关系是什么?
String.Split使用默认的StringSplitOption(定义为StringSplitOption.None)创建一个包含1个字符串的列表,然后在列表中为找到的每个拆分字符添加一个新字符串。
因此,在第一个"
之前,字符串在分割数组中的索引0处,在第一个和第二个"
之间,字符串在数组中的索引1处,在第三个和第二个之间第四,索引2,......
一般规则是:第n个和第(n + 1)个"
之间的字符串位于数组中的索引n处。 (2)
给定的(1)
和(2)
,我们可以得出结论:引用的部分位于分割数组中的奇数索引处。
答案 2 :(得分:9)
由于自定义解析器可能更适合此。
当我有一个涉及括号和空格的特定(并且非常奇怪)的解析要求时,这是我写过的东西,但它足够通用,它几乎可以用于任何分隔符和文本限定符。
public static IEnumerable<String> ParseText(String line, Char delimiter, Char textQualifier)
{
if (line == null)
yield break;
else
{
Char prevChar = '\0';
Char nextChar = '\0';
Char currentChar = '\0';
Boolean inString = false;
StringBuilder token = new StringBuilder();
for (int i = 0; i < line.Length; i++)
{
currentChar = line[i];
if (i > 0)
prevChar = line[i - 1];
else
prevChar = '\0';
if (i + 1 < line.Length)
nextChar = line[i + 1];
else
nextChar = '\0';
if (currentChar == textQualifier && (prevChar == '\0' || prevChar == delimiter) && !inString)
{
inString = true;
continue;
}
if (currentChar == textQualifier && (nextChar == '\0' || nextChar == delimiter) && inString)
{
inString = false;
continue;
}
if (currentChar == delimiter && !inString)
{
yield return token.ToString();
token = token.Remove(0, token.Length);
continue;
}
token = token.Append(currentChar);
}
yield return token.ToString();
}
}
用法是:
var parsedText = ParseText(streamR, ' ', '"');
答案 3 :(得分:9)
您可以使用属于Microsoft.VisualBasic.FileIO
命名空间的TextFieldParser类。 (您需要在项目中添加对Microsoft.VisualBasic
的引用。):
string inputString = "This is \"a test\" of the parser.";
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(inputString)))
{
using (Microsoft.VisualBasic.FileIO.TextFieldParser tfp = new TextFieldParser(ms))
{
tfp.Delimiters = new string[] { " " };
tfp.HasFieldsEnclosedInQuotes = true;
string[] output = tfp.ReadFields();
for (int i = 0; i < output.Length; i++)
{
Console.WriteLine("{0}:{1}", i, output[i]);
}
}
}
生成输出:
0:This
1:is
2:a test
3:of
4:the
5:parser.
答案 4 :(得分:1)
Squazz的回答只是一个小问题..它适用于他的字符串,但如果添加更多项目则不行。例如。
string myString = "WordOne \"Word Two\" Three"
在这种情况下,删除最后一个引号会得到4个结果,而不是3个。
虽然很容易修复..只计算转义字符的数量,如果它不均匀,剥去最后一个(根据你的要求进行调整......)
public static List<String> Split(this string myString, char separator, char escapeCharacter)
{
int nbEscapeCharactoers = myString.Count(c => c == escapeCharacter);
if (nbEscapeCharactoers % 2 != 0) // uneven number of escape characters
{
int lastIndex = myString.LastIndexOf("" + escapeCharacter, StringComparison.Ordinal);
myString = myString.Remove(lastIndex, 1); // remove the last escape character
}
var result = myString.Split(escapeCharacter)
.Select((element, index) => index % 2 == 0 // If even index
? element.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries) // Split the item
: new string[] { element }) // Keep the entire item
.SelectMany(element => element).ToList();
return result;
}
我还将其转换为扩展方法,并使分隔符和转义字符可配置。
答案 5 :(得分:0)
...删除所有空格除 引号
之外的空格
CédricBignon的解决方案几乎是这样做的,但没有考虑到可能会有不均匀的引号。首先检查这个,然后删除多余的,确保我们只在元素真的用引号封装时才停止分裂。
string myString = "WordOne \"Word Two";
int placement = myString.LastIndexOf("\"", StringComparison.Ordinal);
if (placement >= 0)
myString = myString.Remove(placement, 1);
var result = myString.Split('"')
.Select((element, index) => index % 2 == 0 // If even index
? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) // Split the item
: new string[] { element }) // Keep the entire item
.SelectMany(element => element).ToList();
Console.WriteLine(result[0]);
Console.WriteLine(result[1]);
Console.ReadKey();
归功于CédricBignon的逻辑,我只添加了一个保护措施。
答案 6 :(得分:0)
支持双引号。
字符串:
a "b b" "c ""c"" c"
结果:
a
"b b"
"c ""c"" c"
代码:
var list=Regex.Matches(value, @"\""(\""\""|[^\""])+\""|[^ ]+",
RegexOptions.ExplicitCapture)
.Cast<Match>()
.Select(m => m.Value)
.ToList();
可选删除双引号:
Select(m => m.StartsWith("\"") ? m.Substring(1, m.Length - 2).Replace("\"\"", "\"") : m)
结果
a
b b
c "c" c