2017-04-06 32 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

相關問題