2017-04-06 76 views
1

我有一堆的文本字符串,它看起来像这样的事情:正则表达式C#可以在替换中使用一个变量吗?

h1. this is the Header 
h3. this one the header too 
h111. and this 

而且我得到了功能,即假设来处理该文本取决于什么可以说的迭代它被称为

public void ProcessHeadersInText(string inputText, int atLevel = 1) 

所以输出应该看起来像一个下面的被称为

情况下
ProcessHeadersInText(inputText, 2) 

输出应该是:

<h3>this is the Header<h3> 
<h5>this one the header too<h5> 
<h9 and this <h9> 

(最后一个看起来是这样的,因为如果值后h信超过9它想在输出9

于是,我开始考虑使用正则表达式。

这里的例子https://regex101.com/r/spb3Af/1/

(正如你看到的,我想出了正则表达式这样(^(h([\d]+)\.+?)(.+?)$),并试图使用替换就可以了<h$3>$4</h$3>

它几乎是我正在寻找,但我需要在标题级别添加一些逻辑。

是否有可能在替换中添加任何带有变量的工作?

或者我需要找到其他方法? (首先提取所有标题,替换em考虑函数变量和标题的值,并且只有在我使用正则表达式后才写?)

+0

你可以只使用一个委托,而不是只是一个替换字符串。 – Joey

+0

您可以使用MatcEvaluator https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.matchevaluator(v=vs.110).aspx(可能是@Joey在说什么) –

+0

噢,那很棒理念! – DanilGholtsman

回答

1

正则表达式,你可以使用是

^h(\d+)\.+\s*(.+) 

如果你需要确保比赛不会不跨越线路,您可以用[^\S\r\n]代替\s。请参阅regex demo

在C#中进行替换时,将组1的值解析为int,并将Regex.Replace方法内的匹配评估程序中的值递增。

下面是示例代码,这将有助于你:

using System; 
using System.Linq; 
using System.Text.RegularExpressions; 
using System.IO; 
public class Test 
{ 
    // Demo: https://regex101.com/r/M9iGUO/2 
    public static readonly Regex reg = new Regex(@"^h(\d+)\.+\s*(.+)", RegexOptions.Compiled | RegexOptions.Multiline); 

    public static void Main() 
    { 
     var inputText = "h1. Topic 1\r\nblah blah blah, because of bla bla bla\r\nh2. PartA\r\nblah blah blah\r\nh3. Part a\r\nblah blah blah\r\nh2. Part B\r\nblah blah blah\r\nh1. Topic 2\r\nand its cuz blah blah\r\nFIN"; 
     var res = ProcessHeadersInText(inputText, 2); 
     Console.WriteLine(res); 
    } 
    public static string ProcessHeadersInText(string inputText, int atLevel = 1) 
    { 
     return reg.Replace(inputText, m => 
      string.Format("<h{0}>{1}</h{0}>", (int.Parse(m.Groups[1].Value) > 9 ? 
       9 : int.Parse(m.Groups[1].Value) + atLevel), m.Groups[2].Value.Trim())); 
    } 
} 

见我使用.Trim()C# online demo

注上m.Groups[2].Value.比赛\r。你可以使用TrimEnd('\r')来摆脱这个字符。

+1

感谢这样的完整答案,Wiktor! – DanilGholtsman

1

您可以使用像下面使用的正则表达式来解决您的问题。

Regex.Replace(s, @"^(h\d+)\.(.*)$", @"<$1>$2<$1>", RegexOptions.Multiline) 

让我解释一下,你我在做什么

// This will capture the header number which is followed 
// by a '.' but ignore the . in the capture 
(h\d+)\. 

// This will capture the remaining of the string till the end 
// of the line (see the multi-line regex option being used) 
(.*)$  

括号将捕获它变成可以使用的为“$ 1”的第一捕获和“$ 2”为第二撷取

变量
+0

我不认为这完全回答了OP的问题。 h数值需要被操纵以确保它们不超过9并且可以增加一定数量。 –

+0

这很有帮助,谢谢 – DanilGholtsman

1

试试这个:

private static string ProcessHeadersInText(string inputText, int atLevel = 1) 
{ 
    // Group 1 = value after 'h' 
    // Group 2 = Content of header without leading whitespace 
    string pattern = @"^h(\d+)\.\s*(.*?)\r?$"; 
    return Regex.Replace(inputText, pattern, match => EvaluateHeaderMatch(match, atLevel), RegexOptions.Multiline); 
} 

private static string EvaluateHeaderMatch(Match m, int atLevel) 
{ 
    int hVal = int.Parse(m.Groups[1].Value) + atLevel; 
    if (hVal > 9) { hVal = 9; } 
    return $"<h{hVal}>{m.Groups[2].Value}</h{hVal}>"; 
} 

然后只需调用

ProcessHeadersInText(input,2);


它使用Regex.Replace(string, string, MatchEvaluator, RegexOptions)超负荷使用自定义功能评估。

你当然可以简化这个解决方案与内嵌lambda表达式单一的功能:

public static string ProcessHeadersInText(string inputText, int atLevel = 1) 
{ 
    string pattern = @"^h(\d+)\.\s*(.*?)\r?$"; 
    return Regex.Replace(inputText, pattern, 
     match => 
     { 
      int hVal = int.Parse(match.Groups[1].Value) + atLevel; 
      if (hVal > 9) { hVal = 9; } 
      return $"<h{hVal}>{match.Groups[2].Value}</h{hVal}>"; 
     }, 
     RegexOptions.Multiline); 
} 
+0

哦,哇,interesing,从来没有像以前那样使用它(就像在EvaluateHeaderMatch中一样)! – DanilGholtsman

1

在这个线程很多很好的解决方案,但我不认为你真的需要一个正则表达式解决方案为您的问题。乐趣和挑战,在这里非正则表达式的解决方案:

Try it online!

using System; 
using System.Linq; 

public class Program 
{ 
    public static void Main() 
    { 
     string extractTitle(string x) => x.Substring(x.IndexOf(". ") + 2); 
     string extractNumber(string x) => x.Remove(x.IndexOf(". ")).Substring(1); 
     string build(string n, string t) => $"<h{n}>{t}</h{n}>"; 

     var inputs = new [] { 
      "h1. this is the Header", 
      "h3. this one the header too", 
      "h111. and this" }; 

     foreach (var line in inputs.Select(x => build(extractNumber(x), extractTitle(x)))) 
     { 
      Console.WriteLine(line); 
     } 
    } 
} 

我使用C#7嵌套函数和C#6插字符串。如果你愿意,我可以使用更多的传统C#。代码应该易于阅读,如果需要,我可以添加注释。


C#5.0版本

using System; 
using System.Linq; 

public class Program 
{ 
    static string extractTitle(string x) 
    { 
     return x.Substring(x.IndexOf(". ") + 2); 
    } 

    static string extractNumber(string x) 
    { 
     return x.Remove(x.IndexOf(". ")).Substring(1); 
    } 

    static string build(string n, string t) 
    { 
     return string.Format("<h{0}>{1}</h{0}>", n, t); 
    } 

    public static void Main() 
    { 
     var inputs = new []{ 
      "h1. this is the Header", 
      "h3. this one the header too", 
      "h111. and this" 
     }; 

     foreach (var line in inputs.Select(x => build(extractNumber(x), extractTitle(x)))) 
     { 
      Console.WriteLine(line); 
     } 
    } 
} 
+0

最新C#功能吧?仍然不能强迫自己使用电子 – DanilGholtsman

+0

@DanilGholtsman它只是糖,就像lambda而不是代表。 – aloisdg

+0

是的,我知道,只是,你知道,很难得到它的使用 – DanilGholtsman