正则表达式 - 修复CSV - 引用文本限定符

时间:2018-05-21 22:13:03

标签: c# regex ssis

此时我无法控制生成此文件的源系统。

我有一个使用双引号作为文本限定符的csv文件。在合格的文本字段中,我有时会有双引号,表示英寸等。如下所示:

something not qualified,"12" x 12" something qualified, becuase it has a comma",this one is not qualified and needs no fixing a 12" x 12"

这些应该使用以下两组引号进行转义:

something not qualified,"12"" x 12"" something qualified, becuase it has a comma",this one is not qualified and needs no fixing a 12" x 12"

我正在尝试使用c#和regex编写一些清理代码。我可以编写代码来选择,"",之间的所有内容,但我无法弄清楚如何在这些分隔符中获取双引号。

我可以拥有没有限定符(没有逗号)的字段,这些字段可以有一个双引号而且不需要修复。

以下是regexr https://regexr.com/3pq51

中的内容
((?<=,").*(?=",))

4 个答案:

答案 0 :(得分:1)

这是一个非常令人讨厌的问题,我实际上并不确定它很容易解决(甚至可能在100%的时间内解决),并且与魔法接壤。

唯一的好处是它只适用于英寸(所以你声明),你知道有多少个字段。

然而,似乎有太多Degrees of Freedom并且总会给出误报。即你所拥有的只是一个格式错误的 CSV ,存在以下基本问题: -

  • 您无法可靠地确定没有引号的字段位置
  • 如果没有字段,您无法可靠地确定引号的位置。

也许某人有一种启发式方法,但我猜测任何可靠的解决方案都需要返回“我不确定”#34;导致某些情况...

总之,正则表达式无法为您解决此问题。

无论如何,祝你好运,也许最好从另一端攻击这个。

答案 1 :(得分:1)

您输入的字符串很乱,而且可能无法提出防水解决方案。你可以尝试的一件事是捕捉," ... ",之间的所有内容:

[^,]+|,"(.*?)",

如果您的限定字符串中有另一个",,这显然会中断。

Demo

示例代码:

using System;
using System.Text.RegularExpressions;
public class Program
{
    public static void Main()
    {

        string pattern = @"[^,]+|,""(.*?)"",";
        string input = @"something not qualified,""12"" x 12"" something qualified, becuase it has a comma"",this one is not qualified and needs no fixing a 12"" x 12""";
        RegexOptions options = RegexOptions.Multiline;

        foreach (Match m in Regex.Matches(input, pattern, options))
        {
            if(m.Groups[1].Success)
                Console.WriteLine("'{0}'", m.Groups[1].Value);
            else
                Console.WriteLine("'{0}'", m.Value);
        }
    }
}

输出:

something not qualified
12" x 12" something qualified, becuase it has a comma
this one is not qualified and needs no fixing a 12" x 12"

答案 2 :(得分:1)

如果分隔字符串,"",永远不会在带引号的字符串中发生,您可以使用无限的lookbehind或\G来查找此边界。由于\G - 方法更适合并且更快找到匹配或失败,我会继续使用它:

((?:\A|,)"|\G(?!\A))([^"]*)(")(?!,|\Z)

Regex live demo

C#代码(参见现场演示here):

str = Regex.Replace(str, @"((?:\A|,)""|\G(?!\A))([^""]*)("")(?!,|\Z)", @"$1$2$3$3");

正则表达式细分:

  • (开始捕获第一组
    • (?:\A|,)"匹配"
    • 后面的输入字符串或逗号的开头
    • |
    • \G(?!\A)匹配上一场比赛结束的地方
  • )结束捕获第一组
  • ([^"]*)捕捉除"
  • 之外的所有内容
  • (")抓取"
  • (?!,|\Z)不应该使用逗号或输入字符串结尾

答案 3 :(得分:1)

谢谢大家的帮助。它帮助我看到我需要采取分阶段的方法。

首先,我得到了所有内容,“和”,。然后我找到了它们出现的模式中有单引号的模式,并用2个双引号和空格替换。为了以防万一,我每次都这样做。

string matchPattern = "((?<=,\").*?(?=\",))";
string input = "something not qualified,\"12\" x 12\" something qualified, becuase it has a comma\",this one is not qualified and needs no fixing a 12\" x 12\",\"8\" X 8\" sign, plain\",one more";
var newLine = input;

Regex regx = new Regex(matchPattern);
Regex regxReplace = new Regex(@"(?<=\w)""[^\w|\""]");
var matches = regx.Matches(input);

foreach (Match matchingString in matches)
{        

    var value = matchingString.Value;
    if (regxReplace.IsMatch(value))
    {
        changed = true;
        var newReplacementString = regxReplace.Replace(value, "\"\" ");
        newLine = newLine.Replace(matchingString.Value, newReplacementString);
    }
}

return newLine;