正则表达式:替换内部字符串

时间:2010-03-25 12:50:35

标签: c# regex string

我正在使用X12 EDI文件(特别是835s用于医疗保健中的那些人),我有一个特定的供应商正在使用非HIPAA兼容版本(我认为是3090)。问题在于,在特定的细分市场(PLB-再次,对于那些关心的人),他们发送的代码不再受HIPAA标准的支持。我需要找到特定代码,并使用更正后的代码进行更新。

我认为一个正则表达式最适合这个,但我仍然是Regex的新手,我不知道从哪里开始。我目前的方法是将文件转换为字符串数组,找到以“PLB”开头的数组,将其分解为字符串数组,查找代码并更改它。正如你猜测的那样,那些应该(我认为)相当简单的代码非常详细。

以下是我正在寻找的样本:

~PLB|1902841224|20100228|49>KC15X078001104|.08~

以下是我要将其更改为:

~PLB|1902841224|20100228|CS>KC15X078001104|.08~

有什么建议吗?

更新:经过审核,我发现我的问题还不够完善。上面的记录是一个例子,但它不一定是一个特定的格式匹配 - 这个记录和其他一些(在另一个文件中)我必须修复的事情之间有三件事可能会发生变化。他们是:

  • 管道(|)可能是任何非字母数字字符。文件本身将定义哪个字符(通常是Pipe或Asterisk)。
  • >也可以是任何其他非字母数字字符(最常见的是:或>)
  • 紧跟PLB之后的数字集是标识符,可能会改变格式和长度。我在那里只见过数字ID,但从技术上讲它可能是字母数字,并且它不一定是10个字符。

我的计划是将String.Format()与我的Regex匹配字符串一起使用,以便|和>可以用正确的字符替换。

并记录在案。是的,我讨厌ANSI X12。

7 个答案:

答案 0 :(得分:2)

假设“违规”代码始终为49,您可以使用以下内容:

resultString = Regex.Replace(subjectString, @"(?<=~PLB|\d{10}|\d{8}|)49(?=>\w+|)", "CS");

如果它是49分隔符之后的第一个元素,前面是一组8位数,另一个|,一组10位数,另一个|,则查找| ~PLB 1}}和>。它还会查看后跟|,然后是任意数量的字母数字字符,还有一个resultString = Regex.Replace(subjectString, @"(?<=~PLB\1\w+\1\d{8}(\W))49(?=\W\w+\1)", "CS");

根据新的要求(以及.NET是少数允许在lookbehind中重复重复的正则表达式之一的幸运巧合),您可以将其更改为:

|

现在允许任何非字母数字字符作为分隔符而不是>|(但在{{1}}的情况下,它必须始终是相同的),并且限制关于第一个字段的字符数已经松动。

答案 1 :(得分:1)

另一种类似的方法适用于任何有效的X12文件,以便在匹配的段上用另一个数据值替换单个数据值:

public void ReplaceData(string filePath, string segmentName, 
    int elementPosition, int componentPosition, 
    string oldData, string newData)
{
    string text = File.ReadAllText(filePath);

    Match match = Regex.Match(text, 
     @"^ISA(?<e>.).{100}(?<c>.)(?<s>.)(\w+.*?\k<s>)*IEA\k<e>\d*\k<e>\d*\k<s>$");

    if (!match.Success)
        throw new InvalidOperationException("Not an X12 file");

    char elementSeparator = match.Groups["e"].Value[0];
    char componentSeparator = match.Groups["c"].Value[0];
    char segmentTerminator = match.Groups["s"].Value[0];

    var segments = text
        .Split(segmentTerminator)
        .Select(s => s.Split(elementSeparator)
            .Select(e => e.Split(componentSeparator)).ToArray())
        .ToArray();

    foreach (var segment in segments.Where(s => s[0][0] == segmentName &&
                              s.Count() > elementPosition &&
                              s[elementPosition].Count() > componentPosition &&
                              s[elementPosition][componentPosition] == oldData))
    {
        segment[elementPosition][componentPosition] = newData;
    }

    File.WriteAllText(filePath,
        string.Join(segmentTerminator.ToString(), segments
        .Select(e => string.Join(elementSeparator.ToString(), 
            e.Select(c => string.Join(componentSeparator.ToString(), c))
             .ToArray()))
        .ToArray()));
}

使用的正则表达式验证了正确的X12交换包络,并确保文件中的所有段至少包含一个字符名称元素。它还解析了元素和组件分隔符以及段终止符。

答案 2 :(得分:0)

假设您的代码始终是管道字符|之后和大于号>之前的两位数字,您可以这样做:

var result = Regex.Replace(yourString, @"(\|)(\d{2})(>)", @"$1CS$3");

答案 3 :(得分:0)

你可以用正则表达式来分解它。 如果我正确理解你的例子中的| 2之间的2个字符并且&gt;需要是字母而不是数字。

~PLB\|\d{10}\|\d{8}\|(\d{2})>\w{14}\|\.\d{2}~

此模式将与旧模式匹配并捕获|之间的字符和&gt;。然后您可以使用它来修改(在数据库或其他内容中查找)并使用以下模式进行替换:

(?<=|)\d{2}(?=>)

答案 4 :(得分:0)

这将寻找~PLB |#|#|在开始时并在&gt;之前替换2个数字。与CS。

Regex.Replace(testString, @"(?<=~PLB|[0-9]{10}|[0-9]{8})(\|)([0-9]{2})(>)", @"$1CS$3")

答案 5 :(得分:0)

X12协议标准允许在标题中指定元素和组件分隔符,所以任何硬编码“|”的东西和“&gt;”人物最终可能会破裂。由于标准要求用作分隔符的字符(和段终止符,例如“〜”)不能出现在数据中(没有转义序列允许它们被嵌入),因此解析语法非常简单。也许你已经在做类似的事了,但为了便于阅读......

// The original segment string (without segment terminator):

string segment = "PLB|1902841224|20100228|49>KC15X078001104|.08";

// Parse the segment into elements, then the fourth element
// into components (bounds checking is omitted for brevity):

var elements = segment.Split('|');
var components = elements[3].Split('>');

// If the first component is the bad value, replace it with
// the correct value (again, not checking bounds):

if (components[0] == "49")
    components[0] = "CS";

// Reassemble the segment by joining the components into
// the fourth element, then the elements back into the
// segment string:

elements[3] = string.Join(">", components);
segment = string.Join("|", elements);

显然比单个正则表达式更冗长,但解析X12文件就像在单个字符上拆分字符串一样简单。除了固定长度标题(定义分隔符)之外,可以使用Split解析整个事务集:

// Starting with a string that contains the entire 835 transaction set:

var segments = transactionSet.Split('~');
var segmentElements = segments.Select(s => s.Split('|')).ToArray();

// segmentElements contains an array of element arrays,
// each composite element can be split further into components as shown earlier

答案 6 :(得分:0)

我发现的工作如下:

parts = original.Split(record);

        for(int i = parts.Length -1; i >= 0; i--)
        {
            string s = parts[i];
            string nString =String.Empty;
            if (s.StartsWith("PLB"))
            {
                string[] elems = s.Split(elem);
                if (elems[3].Contains("49" + subelem.ToString()))
                {
                    string regex = string.Format(@"(\{0})49({1})", elem, subelem);
                    nString = Regex.Replace(s, regex, @"$1CS$2");
                }

我仍然需要将原始文件拆分成一组字符串,然后评估每个字符串,但接缝现在正在工作。

如果有人知道如何绕过那个字符串。在顶部分开,我很乐意看到一个样本。