【问题标题】:Split using delimiter except when delimiter is escaped使用分隔符拆分,除非分隔符被转义
【发布时间】:2011-05-23 03:18:17
【问题描述】:

我正在使用

读取来自 excel 的剪贴板数据

var stream = (System.IO.Stream) ( Forms.Clipboard.GetDataObject() ).GetData( Forms.DataFormats.CommaSeparatedValue );,

但不幸的是,excel 传递的是单元格文本而不是单元格值。当单元格使用特殊格式(例如千位分隔符)时,列中一系列单元格的剪贴板数据如下所示:

 1,234,123.00    2,345.00    342.00      12,345.00

存储如下:

\" 1,234,123.00 \",\" 2,345.00 \", 342.00 ,\" 12,345.00 \"

当我真正想要的是这样的时候:

 1234123.00, 2345.00, 342.00, 12345.00

我之前一直使用clipData.Split(new string[] { "," }, StringSllitOptions.None)) 函数将我的 CSV 剪贴板数据转换为一系列单元格,但是当存在包含逗号的转义格式文本时,此方法会失败。


我在问是否有人能想出一种方法将此字符串拆分为一组单元格,而忽略在 \" 位内转义的逗号,因为这就是 Excel 选择转义包含逗号的单元格的方式。

简而言之,我怎样才能打开一个包含这个的字符串:

\" 1,234,123.00 \",\" 2,345.00 \", 342.00 ,\" 12,345.00 \"

放入包含以下内容的字符串数组中:

{ "1,234,123.00", "2,345.00", "342.00", "12,345.00" }

不会破坏我解析简单逗号分隔字符串的能力。

*****编辑***

在此处跟进问题(以 DFA 形式表述):Split a string based on each time a Deterministic Finite Automata reaches a final state?

【问题讨论】:

  • 您是否真的看到了一个 \ 后跟一个 " 或者您只是使用 \" 来表示双引号而不是字符串开头的表示。
  • 不能获取其他格式的数据吗?使用 IDataObject.GetFormats 检索可用格式列表,看看是否能找到更好的格式。
  • 好的,我将花时间评估和测试其中几个解决方案,然后回复你们。
  • 许多解决方案都失败了,因为 Excel 并不总是在单元格值周围加上引号,只有当它们包含逗号时。任何使用 "split" 的情况下,如果不使用引号,会避免在引号内意外拆分逗号,则无法正确拆分逗号。

标签: c# excel string clipboard


【解决方案1】:

首先,我之前处理过 Excel 中的数据,您通常看到的是逗号分隔值,如果该值被认为是一个字符串,它将在其周围加上双引号(并且可以包含逗号和双引号)。如果它被认为是数字,则没有双引号。此外,如果数据包含将由双引号分隔的双引号,例如""。所以假设所有这些都是我过去处理这个问题的方式

public static IEnumerable<string> SplitExcelRow(this string value)
{
    value = value.Replace("\"\"", "&quot;");
    bool quoted = false;
    int currStartIndex = 0;
    for (int i = 0; i < value.Length; i++)
    {
        char currChar = value[i];
        if (currChar == '"')
        {
            quoted = !quoted;       
        }
        else if (currChar == ',')
        {
            if (!quoted)
            {
                yield return value.Substring(currStartIndex, i - currStartIndex)
                    .Trim()
                    .Replace("\"","")
                    .Replace("&quot;","\"");
                currStartIndex = i + 1;
            }
        }
    }
    yield return value.Substring(currStartIndex, value.Length - currStartIndex)
        .Trim()
        .Replace("\"", "")
        .Replace("&quot;", "\"");
}

当然,这假设传入的数据是有效的,所以如果你有类似"fo,o"b,ar","bar""foo" 的东西,这将不起作用。此外,如果您的数据包含 &amp;quot;,那么它将被转换为 ",这可能是可取的,也可能不是可取的。

【讨论】:

  • 如果您正在处理来自 Excel 的 csv 转储,情况会变得更糟,因为行由换行符分隔,但单元格可以包含换行符,您必须查看换行符是否“引用”以确定是否它是数据的一部分或新行的开头。
  • 这是这里给出的最佳方法,因为在用逗号分割字符串时,除非它们被引号包围,否则真正需要的是与此相对应的确定性有限自动机的迭代实现问题。虽然正则表达式可以验证字符串是否满足 DFA,但我不知道它能够根据满足的最终状态的每个实例来拆分字符串。因此,通过迭代手动评估 DFA。干杯。
  • 在此处跟进问题:stackoverflow.com/questions/4462168/…
【解决方案2】:

我同意凯尔关于你的字符串可能不一致的观点。

你可以使用凯尔的第一步来代替

string[] vals = Regex.Split(value, @"\s*\"",\s*");

【讨论】:

  • 虽然现在你有两个问题:)
  • @Nat 这是一个不恰当的笑话,也是一个不正确的笑话。首先,人们可能没有意识到您在重复一个笑话,即如果您考虑使用正则表达式解决某些问题,那么您将遇到两个问题。也就是说,您并不是说他的解决方案有任何问题。所以你的笑话在这里是不合适的,因为它可能会被不熟悉它的人误解。其次,一旦你从正则表达式中得到解决方案,你就不再有两个问题,如果它有效,你就会有 0 个问题,所以你的笑话在这种情况下或任何你有解决方案的情况下也是错误的..
【解决方案3】:

您可以尝试使用一些 LINQ:

string excelData = "\\\" 1,234,123.00 \\\",\\\" 2,345.00 \\\", 342.00 ,\\\" 12,345.00 \\\"";

IEnumerable<string> cells = from x in excelData.Split(new string[] { "\\\"" }, StringSplitOptions.RemoveEmptyEntries)
                            let y = x.Trim(',').Trim()
                            where !string.IsNullOrWhiteSpace(y)
                            select y;

或者,如果您不喜欢这个建议,请尝试使用 RegEx 实现类似的模式。

【讨论】:

    【解决方案4】:

    从您的输入示例中,我们可以看到存在三个“不需要的”字符序列:

    \"
    \",
    ,\"
    

    因此,将所有这些序列添加到 Split 方法的输入数组中:

    string[] result = clipData.Split(new[] { @",\""", @"\"",", @"\""" }, 
        StringSplitOptions.None);
    

    这将为您提供一个包含一些空元素的数组。如果这是一个问题,请使用StringSplitOptions.RemoveEmptyEntries 而不是StringSplitOptions.None

    string[] result = clipData.Split(new[] { @",\""", @"\"",", @"\""" }, 
        StringSplitOptions.RemoveEmptyEntries);
    

    【讨论】:

    • 这也会在数字内的千位分隔符处拆分。
    • 我很确定输入可能是123 , 456 , 789,因为 Excel 只在被视为字符串的数据周围加上双引号(在这种情况下,当数据包含逗号时) .在这种情况下,您的解决方案将不起作用。
    • @juharr:你很可能是正确的。有时我会觉得,一旦 Excel 接触到数据,所有的赌注就都落空了,你需要为任何事情做好准备。
    • 是的,正如 juharr 指出的那样,这很复杂,因为只有当单元格包含逗号时才使用转义字符,否则一切通常都是逗号分隔的。
    【解决方案5】:

    有很多方法可以做到这一点。一种不优雅的工作方式是:

    1. 将 \",\" 转换为制表符或其他分隔符(我假设您在示例中遗漏了几个 \" 否则字符串不一致
    2. 去掉所有剩余的逗号
    3. 剥离所有剩余的\"
    4. 将分隔符(例如制表符)转换回逗号

    现在你首先得到了你想要的东西

    【讨论】:

    • 为什么用其他东西代替 \",\" 当你可以分开的时候。此外,我从经验中知道,Excel 并不总是在数据周围加上双引号,因此有可能出现 \"1,234\",123,\"2,345\" 之类的东西。
    • 感谢这个想法。我在" 上拆分,但不想在\" 上拆分,所以我将所有\" 替换为永远不会存在的疯狂的东西,然后将其拆分为",并将疯狂的东西替换为@ 987654326@拆分后。效果很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多