Regex -修复CSV -引号内的引号文本限定符

mo49yndu  于 2023-05-19  发布在  其他
关注(0)|答案(4)|浏览(179)

此时,我无法控制生成此文件的源系统。
我有一个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中的内容

((?<=,").*(?=",))
col17t5w

col17t5w1#

你的输入字符串是一团乱,很可能不可能想出一个无懈可击的解决方案。您可以尝试的一件事是像这样捕获," ... ",之间的所有内容:

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

如果在限定字符串中有另一个",,这显然会中断。
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"
6fe3ivhb

6fe3ivhb2#

如果定界字符串,"",永远不会出现在一个带引号的字符串中,你可以使用无限向后查找或\G来查找这个边界。由于\G-方法在查找匹配或失败时更合适和更快,我将使用它:

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

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

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

Regex细分:

  • (开始捕获组1
  • (?:\A|,)"匹配"后面的输入字符串或逗号的开头
  • |
  • \G(?!\A)匹配上一个匹配结束的位置
  • )捕获组1结束
  • ([^"]*)捕获除"以外的所有内容
  • (")捕获"
  • (?!,|\Z)不应该跟在逗号或输入字符串的末尾
cxfofazt

cxfofazt3#

谢谢大家的帮助。它帮助我看到我需要采取分阶段的方法。
首先我把所有的东西都放在“和”里面。然后我找到模式中有一个双引号的模式,并替换为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;
snz8szmq

snz8szmq4#

这是一个相当棘手的问题,我不确定它是否容易解决(甚至有可能100%解决),并且近乎魔术。
一件好事是这只是英寸(所以你的状态),你知道有多少领域。
然而,似乎有太多的Degrees of Freedom,总是会给予假阳性。也就是说,你所拥有的只是一个格式错误的 CSV,具有以下基本问题:

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

也许有人有一个启发式的方法,但我猜任何可靠的解决方案将需要返回一个“我不确定”的结果在某些情况下…
总而言之,regex不能为你解决这个问题。
也许最好从另一端攻击它。

相关问题