XML文件中的C#正则表达式

Posted

技术标签:

【中文标题】XML文件中的C#正则表达式【英文标题】:C# Regex in XML file 【发布时间】:2020-08-16 20:57:58 【问题描述】:

我有一个 XML 文件,其中多次包含以下字符串:

<Name Area="" Title="@(String) - @(I am) - @(looking) - @(for)" ...</Name>

我想做的是用正则表达式搜索这些字符串,切掉 @() 并将其余部分保存在新的文本文件中。 我已经设法找到与该字符串匹配的模式,计算该模式与该字符串匹配的频率,但我未能挑选和操作它们。

我在 Windows 窗体应用程序中完成所有这些工作。

编辑:

莫顿·博克:

到目前为止,我唯一能做的就是让用户选择要处理的文件以及保存新文件的位置。它正在这样做。我对使用正则表达式的想法失败了。

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Text.RegularExpressions;

    namespace Movitool
    
        public partial class Form1 : Form
        
            public Form1()
            
                InitializeComponent();
            

            public static class Globals
            
                public static string AlrFile = string.Empty;
                public static string AlrFileNeu = string.Empty;
            

            private void btnPfadAuswahl_Click(object sender, EventArgs e)
            

                using (OpenFileDialog fileDialog1 = new OpenFileDialog())
                
                    fileDialog1.Filter = "movalr files (*.movalr)|*.movalr";
                    fileDialog1.RestoreDirectory = true;
                    fileDialog1.InitialDirectory = @"Dokumente\";

                    if (fileDialog1.ShowDialog() == DialogResult.OK)
                    
                        Globals.AlrFile = fileDialog1.FileName;
                        txtPfad.Text = Globals.AlrFile; 
                    
                
            

            private void btnStartAlr_Click(object sender, EventArgs e)
            
                string pattern = @"@(.*?)";
                Regex rgx = new Regex(pattern);

                using (SaveFileDialog fileDialog2 = new SaveFileDialog())
                
                    fileDialog2.InitialDirectory = @"Dokumente";
                    fileDialog2.Title = "Save File";
                    fileDialog2.Filter = "txt files (*.txt)|*.txt";

                    if(fileDialog2.ShowDialog() == DialogResult.OK)
                    
                        Globals.AlrFileNeu = fileDialog2.FileName;
                    
                

                foreach(string Line in File.ReadLines(Globals.AlrFile))                     
                
                    File.AppendAllText(Globals.AlrFileNeu, Line + Environment.NewLine);     
                

                lblStatus.Text = "Fertig!";
            
        
    

【问题讨论】:

您是否使用 RegEx 搜索 XML? IMO,最好将 XML 转储到 XDocument,将字符串(在您的 sn-p 中它们是 Title 属性的值)提取到集合中,然后对字符串中的字符串执行 RegEx收藏。 您需要展示您的尝试,提供足够的代码来复制您的问题等。请查看“如何提问”部分。 【参考方案1】:

尝试以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace ConsoleApplication1

    class Program
    
        const string FILENAME = @"c:\temp\test.txt";
        static void Main(string[] args)
        
            string input = File.ReadAllText(FILENAME);

            string pattern = @"(?'start'@\()(?'middle'[^\)]+)(?'end'\))";

            string output = Regex.Replace(input, pattern, "$middle");

        
    

这是使用您的数据的输出

<?xml version="1.0" encoding="ISO-8859-1" ?>
<Alarms>
<AlarmList>
<Alarm>
<Name Device="" Variable="" Area="1" ThresholdExclusive="0" Enabled="1" OnQualityGood="1" VariableDuration="0" EnableVariable="" EnableDispMsg="" Hysteresis="0" EventsCache="1024"></Name>
<ThresholdList>
<Threshold>
<Name Area="" Title="My - Searched - String" Help="" DurationFormat="" ReadAccessLevel="4294901760" WriteAccessLevel="4294901760">On</Name>
<Execution Condition="2" Threshold="1" ThresholdVar="" ThresholdLow="0" ThresholdVarLow="" VariableStatus="" Severity="10" SeverityVar="" SecDelay="0" RunCommandAtServer="0"/>
<Commands/>
<CommandsOn/>
<CommandsAck/>
<CommandsReset/>
<CommandsOff/>
<Style BackColor="4294967295" TextColor="65535" BlinkBackColor="4294967295" BlinkTextColor="4294967295" Print="1" Log="1" BlinkOnNewAlarm="0" VarTimeStamp="0" SupportAck="0" SupportReset="0" SupportResetConditionOn="0" BmpFile="" SndFile="" BeepEnabled="0" SpeechEnabled="0" RepeatSpeechEverySec="0" EnableSpeechVariable="" PlaysoundContinuosly="0" CommentOnAck="0"/>
<Recipient Attachment="" DispatchingText=""/>
<SendEmail SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendVoice SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendSMS SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendFax SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendAdminAlert SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendMessenger SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<ScriptCode StartSel="0" SelLength="0" OutStatusBar="1" OutLog="1" OutPrinter="1">
</ScriptCode>
</Threshold>
</ThresholdList>
</Alarm>
</AlarmList>
</Alarms>

这里只是使用 xml linq 更改的标题

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1

    class Program
    
        const string FILENAME = @"c:\temp\test.txt";
        static void Main(string[] args)
        
            XDocument doc = XDocument.Load(FILENAME);

            string pattern = @"(?'start'@\()(?'middle'[^\)]+)(?'end'\))";

            foreach(XElement xTitle in doc.Descendants("Name").Where(x => x.Attribute("Title") != null))
            
                string title = (string)xTitle.Attribute("Title");
                Console.WriteLine("Title : " + Regex.Replace(title, pattern, "$middle"));
            
            Console.ReadLine();
        
    

【讨论】:

谢谢你的回答,但我的问题是我不知道字符串的样子,它们总是不同的。 你试过代码了吗?我只是删除了“@(”和关闭的“)”。我刚刚用你的字符串测试过。输入可以是任何东西。 是的,我必须遍历文件,其中我搜索的字符串之前和之后是其他属性。 显然您没有尝试该代码,如果您尝试过,您会看到它有效。我认为您需要阅读 RegEx 上的文档才能真正理解我所做的事情:docs.microsoft.com/en-us/dotnet/standard/base-types/… 我用你的 xml 文件更新了我的代码。该代码有效。看看我的输出。【参考方案2】:

回答jdweng的最后一条评论:

是的,我已经尝试过您的代码。我也尝试将它与 Tim 的答案混合在一起,他说要使用 XDocument。 我现在尝试的是:

            XmlReader xr = new XmlTextReader(Globals.AlrFile);

            lblMatches.Text = "";
            while (xr.Read())
            
                if(xr.NodeType == XmlNodeType.Element)
                
                    if(xr.AttributeCount > 0)
                    
                        while(xr.MoveToNextAttribute())
                        
                            string input = Convert.ToString(xr.Value);
                            string pattern = @"(?'start'@\()(?'middle'[^\)]+)(?'end'\))";
                            string output = Regex.Replace(input, pattern, "$middle");

                            File.AppendAllText(Globals.AlrFileNeu, output + Environment.NewLine);
                        
                    
                
            

            xr.Close();

但我的 xml 输入是这样的:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<Alarms>
<AlarmList>
<Alarm>
<Name Device="" Variable="" Area="1" ThresholdExclusive="0" Enabled="1" OnQualityGood="1" VariableDuration="0" EnableVariable="" EnableDispMsg="" Hysteresis="0" EventsCache="1024"></Name>
<ThresholdList>
<Threshold>
<Name Area="" Title="@(My) - @(Searched) - @(String)" Help="" DurationFormat="" ReadAccessLevel="4294901760" WriteAccessLevel="4294901760">On</Name>
<Execution Condition="2" Threshold="1" ThresholdVar="" ThresholdLow="0" ThresholdVarLow="" VariableStatus="" Severity="10" SeverityVar="" SecDelay="0" RunCommandAtServer="0"/>
<Commands/>
<CommandsOn/>
<CommandsAck/>
<CommandsReset/>
<CommandsOff/>
<Style BackColor="4294967295" TextColor="65535" BlinkBackColor="4294967295" BlinkTextColor="4294967295" Print="1" Log="1" BlinkOnNewAlarm="0" VarTimeStamp="0" SupportAck="0" SupportReset="0" SupportResetConditionOn="0" BmpFile="" SndFile="" BeepEnabled="0" SpeechEnabled="0" RepeatSpeechEverySec="0" EnableSpeechVariable="" PlaysoundContinuosly="0" CommentOnAck="0"/>
<Recipient Attachment="" DispatchingText=""/>
<SendEmail SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendVoice SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendSMS SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendFax SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendAdminAlert SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<SendMessenger SendON="0" SendACK="0" SendRESET="0" SendOFF="0"/>
<ScriptCode StartSel="0" SelLength="0" OutStatusBar="1" OutLog="1" OutPrinter="1">
</ScriptCode>
</Threshold>
</ThresholdList>
</Alarm>
</AlarmList>
</Alarms>

我在新文本文件中得到的输出是:

1
0
1
1
0


0
1024

My - Searched - String


4294901760
4294901760
2
1

0


10

0
0
4294967295
65535
4294967295
4294967295
1
1
0
0
0
0
0


0
0
0

0
0


0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1

我的问题是我只需要 Title 属性之间的文本,并且我有多个警报元素要通过。

【讨论】:

您不需要使用 XDocument。您将结果附加到原始结果中并弄得一团糟。看看我上面发布的结果。

以上是关于XML文件中的C#正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式匹配从 xml 文件中搜索和替换包含占位符标记的文本。 VB.net 或 C#

在 C# 中使用正则表达式列出只有 txt 文件的目录

C# 正则表达式:将空格替换为 XML 标记

匹配 XML 字符串的正则表达式在 C# 中具有开始和结束标记

正则表达式 (C#):匹配 > < 或(非法 XML 字符)但仅当包含在引号内时

使用正则表达式c#替换文档中的文本字段