C#:从带引号的字符串中删除分隔符字符

5

我是一名程序员,正在编写一个程序,需要从文本文件中的带引号字符串中删除分隔符字符。

例如:

"Hello, my name is world"

必须是:

"Hello my name is world"

这听起来一开始很容易(我也这么想),但你需要检测引用的开始和结束,然后搜索该特定字符串以查找分隔符。如何做到?
我尝试过一些正则表达式,但只是让自己感到困惑!
有任何想法吗?甚至只是为了开始推动球 rolling,我完全被卡住了。

1
你是为了让它能够被CSV解析而去除逗号吗?如果是这样,那么有正则表达式可用于提取遵循“标准”CSV格式的令牌。如果不是,请忽略此评论。 - Brad Christie
8个回答

4
string pattern = "\"([^\"]+)\"";
value = Regex.Match(textToSearch, pattern).Value;

string[] removalCharacters = {",",";"}; //or any other characters
foreach (string character in removalCharacters)
{
    value = value.Replace(character, "");
}

1
在使用正则表达式中的点时,你必须小心;在 .Net 中它是贪婪的(意味着它会从第一个开放引号开始,并在最后一个关闭引号结束)。因此,你会失去其中所有逗号和分号。然而,你可以这样做:string pattern = "\"([^\"]+)\""; 它将从开放引号开始并在找到另一个引号时停止。 - Mark Avenius
谢谢,我会更新这个例子。我对正则表达式还比较新,所以感谢你的提示。 - Matt

2

为什么不尝试使用 Linq 来完成呢?

var x = @" this is a great whatever ""Hello, my name is world"" and all that";

var result = string.Join(@"""", x.Split('"').
Select((val, index) => index%2 == 1 ? 
val.Replace(",", "") : val).ToArray());

2
使用带有前瞻的正则表达式模式,模式应为:"\"(?=[^\"]+,)[^\"]+\""
其中,\"匹配开头的双引号。前瞻(?=[^\"]+,)会尝试匹配引号内的逗号。接下来,只要不是双引号就匹配字符串的其余部分[^\"]+,然后匹配结束的双引号\"
使用Regex.Replace可以紧凑地修改结果并删除不需要的逗号。
string input = "\"Hello, my name, is world\"";
string pattern = "\"(?=[^\"]+,)[^\"]+\"";
string result = Regex.Replace(input, pattern, m => m.Value.Replace(",", ""));
Console.WriteLine(result);

1
你想要编写的是一个“词法分析器”(或者叫“标记生成器”),它会逐个字符读取输入并将其分解成标记。这通常是编译器中解析的第一步。词法分析器会将文本分解成一系列标记(例如字符串字面量、标识符、“(”等)。然后,解析器会使用这些标记来生成语法树。
在你的情况下,你只需要一个词法分析器。你将有两种类型的标记:“带引号的字符串”和“其他所有内容”。
然后,你只需要编写代码将输入分解成标记即可。默认情况下,任何东西都是“其他所有内容”的标记。当你看到一个引号时,字符串标记就开始了,并且在看到下一个引号时结束。如果你正在阅读源代码,你可能需要处理像“\”或“””这样的特殊情况。
完成后,你可以迭代标记并对“字符串”标记进行任何所需的处理。

0

所以我猜你有一些带有很多引号的长文本?我会创建一个方法,类似于以下操作:

  1. 遍历字符串直到遇到第一个"
  2. 然后取出子字符串直到下一个",并进行 str.Replace(",", "") 操作,同时替换任何其他想要替换的字符。
  3. 然后继续遍历直到遇到下一个",并一直进行直到结束。

编辑

我刚刚想到了一个更好的方法。这个怎么样:

  string mycompletestring = "This is a string\"containing, a quote\"and some more text";
  string[] splitstring = mycompletestring.Split('"');
  for (int i = 1; i < splitstring.Length; i += 2) {
    splitstring[i] = splitstring[i].Replace(",", "");
  }
  StringBuilder builder = new StringBuilder();
  foreach (string s in splitstring) {
    builder.Append(s + '"');
  }
  mycompletestring = builder.ToString().Substring(0, builder.ToString().Length - 1);

我认为应该有更好的方法将字符串组合成一个带有“”的字符串,但我不知道更好的方法,所以请随意在这里建议一个好的方法 :)


这听起来像是我需要做的事情...实际上我正在使用StreamReader读文件,但是我正在使用ReadLine()逐行读取。我应该对每一行都这样做吗? - New Start
为什么不一次性读取整个文件,使用我在帖子的 EDIT 部分中提供的方法,然后再将其写入文件呢?逐行读取会在引号开始于一行,结束于另一行时出现混乱(至少对于我的实现是这样,但如果您自己实现的话当然也可以修复它)。 - Øyvind Bråthen
你不一定想对每一行都这样做,以防引号跨越多行。你需要使用ReadToEnd一次性获取所有文本,然后执行建议的操作。 - Mark Avenius

0
我曾在使用的一款翻译平台中,需要实现类似的需求。我采用了以下方法(以下是我从应用程序中复制/粘贴的代码):
        protected virtual string[] delimitCVSBuffer(string inputBuffer) {
        List<string> output       = new List<string>();
        bool insideQuotes         = false;
        StringBuilder fieldBuffer = new StringBuilder();
        foreach (char c in inputBuffer) {
            if (c == FieldDelimiter && !insideQuotes) {
                output.Add(fieldBuffer.Remove(0, 1).Remove(fieldBuffer.Length - 1, 1).ToString().Trim());
                fieldBuffer.Clear();
                continue;
            } else if (c == '\"')
                insideQuotes = !insideQuotes;
            fieldBuffer.Append(c);
        }
        output.Add(fieldBuffer.Remove(0, 1).Remove(fieldBuffer.Length - 1, 1).ToString().Trim());
        return output.ToArray();
    }

这里再提供一些背景信息... 输入将是一堆用逗号分隔的带引号字符串,例如:"abc123","123abc","blah",它将返回一个字符串数组,其中包含引号内的文本。从那里开始,您可以进行任何所需的字符替换。 "FieldDelimiter" 可以是您指定的任何字符,但在这种情况下它是逗号。 - Brosto
如果您想这样做,为什么不直接使用string.Split('"'),并返回所有偶数索引的字符串呢? - Øyvind Bråthen
它是可配置的,因此我可以传递我选择的分隔符。 - Brosto
嗯,我想我现在明白你的意思了...我猜我走了很远的路来做一些简单的事情。谢谢你的建议!;-) - Brosto

0

好的,这有点古怪,但它有效。

首先,您根据"字符将字符串分成几个部分:

string msg = "this string should have a comma here,\"but, there should be no comma in this bit\", and there should be a comma back at that and";

var parts = msg.Split('"');

然后您需要在"字符上将字符串重新连接在一起,在删除每个其他部分中的逗号之后:

string result = string.Join("\"", RemoveCommaFromEveryOther(parts));

删除函数的代码如下:

IEnumerable<string> RemoveCommaFromEveryOther(IEnumerable<string> parts)
{
    using (var partenum = parts.GetEnumerator())
    {
        bool replace = false;
        while (partenum.MoveNext())
        {
            if(replace)
            {
                yield return partenum.Current.Replace(",","");
                replace = false;
            }
            else
            {
                yield return partenum.Current;
                replace = true;
            }
        }
    }
}

这需要你在代码中包含一个 System.Collections.Generic 的 using 指令。


-1

有很多方法可以做到这一点:

查看函数string.Split()string.IndexOfAny()

您可以使用string.Split(new char[] {',',' '}, StringSplitOption.RemoveEmptyEntries)将短语分割成单词,然后使用StringBuilder类将单词组合在一起。

使用string.Replace("[char to remove goes here]"',"")多次调用每个要删除的字符也可以实现。

编辑:

调用string.Split(new char[] {'\"'}, StringSplitOption.RemoveEmptyEntries)以获取在引号(")之间的字符串数组,然后对每个字符串调用Replace,最后使用StringBuilder将字符串组合在一起。


1
提示:您可以将string.Split(new char[] {' " '})编写为string.Split('“')来处理引号。请只返回翻译后的文本内容,不要进行解释。 - Øyvind Bråthen
你的编辑不起作用,因为这与调用 thestring.replace("\", "") 是一样的,你需要在每个其他字符串中替换逗号,并且 StringSplitOption.RemoveEmptyEntries 意味着如果你的字符串以引号开头并且丢失任何空引号块,则得到错误的字符串顺序。-1 - Matt Ellen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接