在(潜在的)多行字符串中查找以特定值开头和结尾的值

时间:2013-01-17 18:20:20

标签: c# replace

我确定这个问题已被问到某个地方(也许在这里),但我找不到任何信息,这可能是由于我不确定如何准确描述它。

基本上,我正在寻找一个高级查找和替换。替换我确定我可以弄清楚它是什么,但现在我无法让这个发现工作。

在应用程序中,有很多htm文件被加载。用户选择文件并使用它执行操作。完成此操作后,我希望系统再次扫描文件以确保没有问题。例如,此字符串可能出现在htm文件中:

<?strange_tag_start 
     name="var_value" ?>Name<?strange_tag_end ?>

而且,是的,它可以在这样的线条之间被打破。除非发生这种情况,否则上述问题不是问题:

<?strange_tag_start 
     name="var_value" ?><?strange_tag_start 
     name="var_value" ?>Name<?strange_tag_end ?><?strange_tag_end ?>

换行符可能不同。我想要做的是在文档中搜索包含<?strange_tag然后包含<?strange_tag_end ?>的字符串。如果它找到了,我想在字符串中检查是否有另一个<?strange_tag_start或另一个<?strange_tag_end ?>

我最初尝试读取文件并获取特定值的每个索引,然后尝试比较它们。但是,文件中可能存在以下内容,这些都是完全正常的,但系统会找到它们并为我标记它们:

<?strange_tag_start 
     name="var_value" ?>Name<?strange_tag_end ?> There is other text here
and some more text on another line. Then this <?strange_tag_start name="var_value"
             ?>Name<?strange_tag_end ?> is present.

它归结为一个系统(例如某些应用程序中存在的系统),其中指定了字符串的开头,指定了字符串的结尾,然后系统检查它是否包含字符串。

如果这没有意义,或者你需要更多澄清,我可以这样做。

更新

让我澄清一下。我有以下多行字符串:

I want to preserve<?start_foo  
                bar="value" ?> the content  
<?start_baz qux="value" ?>Name  
<?end-baz_qux ?>that is between weird tags.

我想找<?start_foo bar="value" 我还想找到<?end-baz_qux ?>(注意:其中可能有两个紧挨着。) 找到后,我想检查该字符串中是否有另一个<?start_foo bar=(注意:该标签中的“值”也可能不同。) 然后我想删除不应该存在的中间内容,所以我最终得到:

I want to preserve<?start_foo  
                bar="value" ?> the content 
<?end-baz_qux ?>that is between weird tags.

这是另一个希望让它更清晰的例子:

Back <?rh-udv_start name="ctrl_btn" ?><?rh-udv_start name="ctrl_btn" 
    ?>button<?rh-udv_end ?><?rh-udv_end ?> to

在进行搜索之后,我应该最终得到这个:

Back <?rh-udv_start name="ctrl_btn" ?>button<?rh-udv_end ?> to

基本上,我正在寻找一种说法:

  1. 使用VALUE_X找到一个“开头”的字符串(误导为“开头”可能位于字符串的中间)。
  2. 如果找到,请在其后找到VALUE_Y(如果有VALUE_X,应始终找到它。)
  3. 在VALUE_Y之后检查是否还有另一个VALUE_Y。
  4. 通过VALUE_Y检查VALUE_X字符串内部是否包含另一个VALUE_X。
  5. 如果还有其他VALUE_X,请将其删除。如果在VALUE_Y之后立即有 ,则删除第二个VALUE_Y。

2 个答案:

答案 0 :(得分:2)

我相信

<\?.*?\?>

可以找到大多数正则表达式的标签(包括Visual Studio的 - 不确定你使用的是什么)。

如果您还想更换奇怪标签之间的内容,那么请您告诉我们一个更现实的例子吗?确切地知道您要匹配的内容(或一些非常接近的近似值)以提供正确的正则表达式至关重要。例如

<?start_strange_tag blah="foo"?>Name<?end_strange_tag?>

非常不同
<?foo bar="baz"?>Name<?/foo?>

不同
<?start_foo bar="baz"?>Name<?foo_end?>

<强>更新

根据您在下面的评论,我将假设您有一个如下所示的文档:

I want to preserve<?start_foo  
                    bar=\"value\" ?> the content  
<?start_baz qux=\"value\" ?>Name  
<?end-baz_qux ?>that is not between weird tags.

并且您希望结果为:

I want to preserve the content  
that is not between weird tags.

我还假设您正在使用.NET正则表达式程序集(而不是Visual Studio内置的正则表达式。是的,它们是不同的。)

如果是这种情况,那么您可以使用以下内容:

static void Main( string[] args )
{

    string l_input =
        "I want to preserve<?start_foo \n" + 
        "                    bar=\"value\" ?> the content\n" +
        "<?start_baz qux=\"value\" ?>Name\n" +
        "<?end-baz_qux ?>that is not between weird tags.";

    string[] l_singleTags = { "foo" };
    string[] l_multiTags = { "baz" };

    // Removing the single tags is easy:

    foreach ( var l_singleTag in l_singleTags )
        l_input = Regex.Replace( l_input, @"<\?start_" + Regex.Escape( l_singleTag ) + @"\b.*?\?>", "", RegexOptions.Singleline );

    // Removing the multi tags is not too bad:

    foreach ( var l_multiTag in l_multiTags )
        l_input = Regex.Replace( l_input, @"<\?start_" + Regex.Escape( l_multiTag ) + @" (?<param>\w+).*?\?>.*?<\?end-" + Regex.Escape( l_multiTag ) + @"_\k<param>.*?\?>", "", RegexOptions.Singleline );

    Console.WriteLine( l_input );

    Console.ReadKey( true );

}

l_input变为:

I want to preserve the content  
that is not between weird tags.

更新2

在回答您的问题更新时,请尝试以下代码:

static void Main( string[] args )
{

    string l_input =
        "Back <?rh-udv_start name=\"ctrl_btn\" ?><?rh-udv_start name=\"ctrl_btn\"" +
        "   ?>button<?rh-udv_end ?><?rh-udv_end ?> to";

    l_input = Regex.Replace( l_input, @"<\?(?<tagname>[-a-z]+_[a-z]+).*?\?>(?=<\?\k<tagname>)", "", RegexOptions.Singleline );

    Console.WriteLine( l_input );

    Console.ReadKey( true );

}

l_input变为:

Back <?rh-udv_start name="ctrl_btn"   ?>button<?rh-udv_end ?> to

它只是查找重复标记并删除它。例如:

<?a_start foo="bar"?><?a_start    foo="bar"
?>

第一个标签将被删除,只留下:

<?a_start    foo="bar"
?>

与结束标签相同。代码不会容忍标签之间的空格或内容(在这种情况下,它不会删除任何标签)。在您拥有所需内容之前,请随意使用该示例。

答案 1 :(得分:0)

您可以使用Html Agility Pack。我已经将它用于类似的东西,在HTML中定位引文并用序号替换ID。在我的情况下,搜索和替换看起来像这样:

var doc = new HtmlDocument();
doc.LoadHtml(html);
// find using xpath expression
var citeNodes = doc.DocumentNode.SelectNodes("//cite[@data-citationid]");
foreach (var node in citeNodes)
{
    // do some other stuff
    node.Name = "a";
    node.SetAttributeValue("id", "r" + citation.CitationId);
    node.InnerHtml = "[" + citation.Ordinal + "]";
}
return doc.DocumentNode.InnerHtml;