【问题标题】:Find and Replace RegEx with wildcard search and addition of value使用通配符搜索和添加值查找和替换 RegEx
【发布时间】:2010-05-11 00:26:43
【问题描述】:

以下代码来自我在 SO 上提出的其他问题。每个人都非常乐于助人,我几乎掌握了 RegEx,但我遇到了另一个障碍。


简而言之,这就是我基本上需要做的事情。我需要将文本文件中的这一行加载到我的内容变量中:


X17.8Y-1.Z0.1G0H1E1


我需要对 X 值、Y 值、Z 值和 H 值进行通配符搜索。完成后,我需要将其写回我的文本文件(我知道如何创建文本文件,所以这不是问题)。


X17.8Y-1.G54G0T2
G43Z0.1H1M08


我有这里的好心用户给我的代码,除了我需要在第一行的末尾创建 T 值,并使用 H 中的值并将其增加 1 作为 T 值。例如:


X17.8Y-1.Z0.1G0H5E1

将翻译为:

X17.8Y-1.G54G0T6
G43Z0.1H5M08

T 值为 6,因为 H 值为 5。



我有可以做所有事情的代码(执行两个 RegEx 函数并将代码行分成两个新行并添加一些新的 G 值)。但我不知道如何将 T 值添加回第一行并将其增加 1 的 H 值。这是我的代码:

  StreamReader reader = new StreamReader(fDialog.FileName.ToString());
  string content = reader.ReadToEnd();
  reader.Close();

  content = Regex.Replace(content, @"X[-\d.]+Y[-\d.]+", "$0G54G0");
  content = Regex.Replace(content, @"(Z(?:\d*\.)?\d+)[^H]*G0(H(?:\d*\.)?\d+)\w*", "\nG43$1$2M08"); //This must be created on a new line



这段代码非常适合:

X17.8Y-1.Z0.1G0H5E1

并将其变成:

X17.8Y-1.G54G0
G43Z0.1H5M08



但我需要把它变成这样:


X17.8Y-1.G54G0T6
G43Z0.1H5M08

(注意T值被添加到第一行,即H值+1 (T = H + 1)。

有人可以修改我的 RegEx 语句,以便我可以自动执行此操作吗?我试图将我的两个 RegEx 语句合并为一行,但我失败了。


Update1:Stephen 在下面的 cmets 中建议,“正则表达式中没有算术运算符,您需要使用一个组来提取 H值,将其转换为 int,加一并构建一个新字符串。”。但我不知道如何在 C# 代码中执行此操作。

【问题讨论】:

  • 没有必要在标题中加上“C#”,因为你已经在标签中找到了它。此外,C# 不支持正则表达式,因此关于“C# Regex”的问题没有任何意义。
  • AFAIK,正则表达式中没有算术运算符,您需要使用一个组来提取 H 值,将其转换为 int,添加一个并构建一个新字符串。
  • @Stephen 我将如何在代码中执行此操作?谢谢。
  • @JohnSaunders 感谢您的提醒。

标签: c# regex replace find wildcard


【解决方案1】:

最简单的方法是使用一个简单的程序,该程序使用一些捕获(命名)组的正则表达式模式,我有一点空闲时间,所以你开始吧:

程序.cs

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            const string InputFileName = @"input.txt";
            const string OutputFileName = @"output.txt";

            List<Line> parsedLineList = new List<Line>();

            using (StreamReader sr = new StreamReader(InputFileName))
            {
                string inputLine;
                int lineNum = 0;

                while ((inputLine = sr.ReadLine()) != null)
                {
                    lineNum++;

                    Line parsedLine = new Line(inputLine);

                    if (parsedLine.IsMatch)
                    {
                        parsedLineList.Add(parsedLine);
                    }
                    else
                    {
                        Debug.WriteLine("Line {0} did not match pattern {1}", lineNum, inputLine);
                    }
                }
            }

            using (StreamWriter sw = new StreamWriter(OutputFileName))
            {
                foreach (Line line in parsedLineList)
                {
                    sw.WriteLine(line.ToString());
                }
            }
        }
    }
}

input.txt 包含:

X17.8Y-1.Z0.1G0H1E1

这个程序创建 output.txt 包含:

X17.8Y-1.G54G0T2
G43Z0.1H1M08

Program.cs 中的上述代码需要以下简单的 Line 和 Fragment 类定义:

Line.cs

namespace Fragments
{
    class Line
    {
        private readonly static Regex Pattern =
            new Regex(@"^(?<X>X[^Y]+?)(?<Y>Y[^Z]+?)(?<Z>Z[^G]+?)(?<G>G[^H]+?)(?<H>H[^E]+?)(?<E>E[^$])$");

        public readonly string OriginalText;

        public string Text
        {
            get
            {
                return this.X.ToString() + this.Y.ToString() + this.G54.ToString() + this.G.ToString() + this.T.ToString() + Environment.NewLine +
                       this.G43.ToString() + this.Z.ToString() + this.H.ToString() + this.M08.ToString();
            }
        }

        public readonly bool IsMatch;

        public Fragment X { get; set; }
        public Fragment Y { get; set; }
        public readonly Fragment G54 = new Fragment("G54");
        public Fragment G { get; set; }
        public Fragment T { get; set; }
        public readonly Fragment G43 = new Fragment("G43");
        public Fragment Z { get; set; }
        public Fragment H { get; set; }
        public readonly Fragment M08 = new Fragment("M08");
        public Fragment E { get; set; }

        public Line(string text)
        {
            this.OriginalText = text;
            Match match = Line.Pattern.Match(text);
            this.IsMatch = match.Success;

            if (match.Success)
            {
                this.X = new Fragment(match.Groups["X"].Value);
                this.Y = new Fragment(match.Groups["Y"].Value);
                this.G = new Fragment(match.Groups["G"].Value);
                this.Z = new Fragment(match.Groups["Z"].Value);
                this.H = new Fragment(match.Groups["H"].Value);
                this.E = new Fragment(match.Groups["E"].Value);

                this.T = new Fragment('T', this.H.Number + 1.0);
            }
        }

        public override string ToString()
        {
            return this.Text;
        }
    }
}

片段.cs

namespace Fragments
{
    class Fragment
    {
        private readonly static Regex Pattern =
            new Regex(@"^(?<Letter>[A-Z]{1})(?<Number>.+)$");

        public readonly string Text;
        public readonly bool IsMatch;

        public readonly char Letter;
        public readonly double Number;

        public Fragment(string text)
        {
            this.Text = text;
            Match match = Fragment.Pattern.Match(text);
            this.IsMatch = match.Success;

            if (match.Success)
            {
                this.Letter = match.Groups["Letter"].Value[0];
                string possibleNumber = match.Groups["Number"].Value;

                double parsedNumber;
                if (double.TryParse(possibleNumber, out parsedNumber))
                {
                    this.Number = parsedNumber;
                }
                else
                {
                    Debug.WriteLine("Couldn't parse double from input {0}", possibleNumber);
                }
            }
            else
            {
                Debug.WriteLine("Fragment {0} did not match fragment pattern", text);
            }
        }

        public Fragment(char letter, double number)
        {
            this.Letter = letter;
            this.Number = number;
            this.Text = letter + number.ToString();
            this.IsMatch = true;
        }

        public override string ToString()
        {
            return this.Text;
        }
    }
}

创建一个新的 C# 控制台应用程序项目,添加这三个文件,更新您的 using 语句,然后您就可以开始了。您可以非常轻松地更改 Program.cs 中的代码,以从 Main 的命令行参数中读取输入和输出文件名,从而使程序可重用。

【讨论】:

  • 非常感谢您花时间为我做这件事。我非常感激。谢谢。
【解决方案2】:

我不确定仅使用正则表达式就可以做到这一点,即使可以,考虑到代码的可维护性,我也不会那样实现它。您可以使用 RegEx 轻松完成的操作是将您需要的部分捕获到组中,并从中创建输出表达式。 这是代码:

System.Text.StringBuilder content = new System.Text.StringBuilder();
using (var reader = new StreamReader(fDialog.FileName.ToString()))
{
    string line = reader.ReadLine();
    while (line != null)
    {
        var matchingExpression = Regex.Match(line, @"(X[-\d.]+)(Y[-\d.]+)(Z(?:\d*\.)?\d+)[^H]*G0H((?:\d*\.)?\d+)\w*");

        content.AppendFormat(
            System.Globalization.CultureInfo.InvariantCulture,
            "{0}{1}G54G0T{2}\n",
            matchingExpression.Groups[0].Value,
            matchingExpression.Groups[1].Value,
            Int32.Parse(matchingExpression.Groups[3].Value) + 1);
        content.AppendFormat(
            System.Globalization.CultureInfo.InvariantCulture,
            "G43{0}H{1}M08\n", 
            matchingExpression.Groups[2].Value, 
            matchingExpression.Groups[3].Value);

        line = reader.ReadLine();
    }
}

要得到你应该做的输出字符串:

content.ToString();

【讨论】:

  • 快速浏览您的代码,我看不到您将 T 值添加回 G54G0 末尾的位置(例如 G54G0T6;如果 H 是 H5)。谢谢。
  • 我无法让您的代码正确执行。它有错误,例如“字符串”不包含 AppendLine 的定义。 AppendFormat 出现同样的错误,CultureInfo 在当前上下文中不存在。
  • AppendLine 和 AppendFormat 是 StringBuilder 类的方法,而不是字符串(这是我的代码 sn-p 上的“内容”类型)。要使用它和 CultureInfo,您应该添加“使用 System.Text;”和“使用 System.Globalization;”在 .cs 文件的顶部(显然没有引号)。另外,您对 T 值是正确的,我放错了捕获并将其值加 1 的正则表达式(它在我的代码 sn-p 的第二行)。稍后我将重新创建正则表达式并更正 sn-p。
猜你喜欢
  • 2013-10-17
  • 2017-05-18
  • 2016-07-21
  • 2016-04-09
  • 1970-01-01
  • 2011-02-16
  • 2015-01-04
  • 1970-01-01
  • 2011-02-17
相关资源
最近更新 更多