0

我想做的是打开一个文件并搜索“searchText”。我想用一个新链接替换文件中它的所有实例,这实际上只是带有锚链接的文件名,所以它不是打开 javascript,而是转到页面中的另一个点。

到目前为止,我所拥有的是:

private void writeNotes(){
        StreamReader reader = new StreamReader(openFileDialog1.FileName);
        string content = reader.ReadToEnd();

        reader.Close();

        string fileName = openFileDialog1.SafeFileName;
        string searchText = "<a class=\"x-fn\" href=\"javascript:void(0);\">";
        string replaceText = "<a class=\"x-fn\" href=\"" + fileName + "#fn" + "\">";

        content = Regex.Replace(content, searchText, replaceText);

        StreamWriter writer = new StreamWriter(openFileDialog1.FileName);
        writer.Write(content);
        writer.Close();

但是,在写入和关闭之后......我打开文件并没有进行任何更改。除此之外,我想做的是为每个替换实例添加一个在“#fn”之后计数的数字。所以,基本上,每次我用另一个替换 javascript 链接时,我希望它是:

<a class="x-fn" href="fileName#fn1">

然后当我替换 javascript 的第二个实例时,它显示为

<a class="x-fn" href="fileName#fn2">

等等...

我想我必须计算javascript出现的次数,替换它,并使用for循环遍历所有新链接并在最后添加#fn(n)?

4

2 回答 2

2

您的问题是您有元字符(在这种情况下,“void(0)”中的打开和关闭括号)。不是表示文字的打开和关闭括号,而是创建一个正则表达式组,这会导致匹配失败。如果您使用反斜杠转义括号,它将按预期工作。

但是,由于您只是匹配字符串文字,因此您根本不需要使用正则表达式;使用起来会更快string.Replace

至于你问题的第二部分,这有点棘手。据我所知,没有简单的方法可以做到这一点,因此最好的方法是在输入中查找您的搜索文本,然后StringBuilder随着您的前进建立 a ,增加一个计数变量。在下面的示例中,为简单起见,单词“the”被替换为“(0)”和“(1)”,但您可以很容易地根据您的问题调整它。

var content = "the quick brown fox jumped over the lazy dog";
var searchText = "the";
var sb = new StringBuilder();
var idx = -1; // will hold the index of our search text
var uncopiedIdx = 0; // the start index of what hasn't been copied yet
var replacementCount = 0;
while( (idx = content.IndexOf( searchText, idx+1 )) != -1 ) {
    // copy everything leading up to our search text
    sb.Append( content.Substring( uncopiedIdx, idx-uncopiedIdx ) );
    // copy the replacement text, with the replacement count
    var replacement = "(" + replacementCount++ + ")";
    sb.Append( replacement );
    // skip over the search text
    uncopiedIdx = idx + searchText.Length;
}
// copy everything after the last match
sb.Append( content.Substring( uncopiedIdx ) );
于 2012-07-09T18:30:55.493 回答
1

您可以使用 MatchEvaluator 一次完成所有操作。
像这样的东西-

C#

string content = 
 @"
     <a class=""x-fn"" href=""javascript:void(0);"">
     <a class='x-fn' href = ""javascript:void(0); "">
     <a href='javascript:void(0);' class=x-fn >
     <a class=""x-fn"" href=javascript:void(0); >
     <a 'hello' href=javascript:void(0); world class=x-fn >
  ";
 string fileName = "FILE";

 Regex jsRx =  new Regex(
  @"
     <a 
         (?=\s) 
         (?= 
             (?: [^>""']|""[^""]*""|'[^']*')*? (?<=\s)
             class \s*=
             (?:
                 (?> \s* (['""])  \s* x-fn  \s* \1 )         # (1) quote
               | (?> (?!\s*['""]) \s* x-fn  (?=\s|>)   )
             )
         )
         (?= 
             ( (?: [^>""']|""[^""]*""|'[^']*')*? ) (?<=\s)       # (2) - before 'href'
             href \s*=
             (?:
                 (?> \s* (['""])  \s* javascript:void\(0\); \s* \3   )   # (3) quote
               | (?> (?!\s*['""]) \s* javascript:void\(0\); (?=\s|>) )
             )
             ( (?> (?:"".*?""|'.*?'|[^>]?)+ ) )                  # (4) - after 'href'
         )
         (?> \s+ (?:"".*?""|'.*?'|[^>]*?)+ 
     >        
         ) (?<! /> )
  ", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);

 int counter = 0;
 string contentNew = jsRx.Replace( content, delegate(Match match)
 {
     return "<a" + match.Groups[2] + "href=\"" + fileName + "#fn" + (counter++) + "\"" + match.Groups[4] + ">";
 });

 Console.WriteLine( contentNew );

输出

<a class="x-fn" href="FILE#fn0">
<a class='x-fn' href="FILE#fn1">
<a href="FILE#fn2" class=x-fn >
<a class="x-fn" href="FILE#fn3" >
<a 'hello' href="FILE#fn4" world class=x-fn >
于 2012-07-09T20:14:13.127 回答