2013-11-26 3 views
1

Я написал утилиту, которая открывает текстовый файл, загружает как строку и выполняет функцию поиска/замены, используя RegEx.Replace.Regex.Replace с большими строками и обратными косыми чертами

Он делает это во многих файлах, пользователь указывает его в папку, вводит строку поиска, заменяет строку и все файлы в папке, содержащие строку в файле, заменяются.

Это отлично работает, пока я не попробую его с обратной косой чертой, где он падает.

Довольно просто:

newFileContent = Regex.Replace(fileContent, @findString, @replaceString, RegexOptions.IgnoreCase); 

fileContent = содержимое файла на основе текста. он будет содержать возврат каретки.

FindString = введен пользователь строка для поиска

replaceString = введенный пользователя строки, чтобы заменить найденную строку с

Я пытался добавить некоторую логику, чтобы противостоять действовать обратные косые черты, как показано ниже, но это не удается с незаконным в конце рисунка.

if (culture.CompareInfo.IndexOf(findString, @"\") >= 0) 
    { 
     Regex.Replace(findString, @"\", @"\\"); 
    } 

Что нужно сделать, чтобы успешно справиться с обратными косыми чертами, чтобы они могли быть частью логики поиска/замены?

Полный блок кода ниже.

//open reader 
       using (var reader = new StreamReader(f,Encoding.Default)) 
       { 
        //read file 
        var fileContent = reader.ReadToEnd(); 

        Globals.AppendTextToLine(string.Format(" replacing string")); 

        //culture find replace 
        var culture = new CultureInfo("en-gb", false); 
        //ensure nothing has changed 
        if (culture.CompareInfo.IndexOf(fileContent, findString, CompareOptions.IgnoreCase) >= 0) 
        { 

         //if find or replace string contains backslahes 
         if (culture.CompareInfo.IndexOf(findString, @"\") >= 0) 
         { 
          Regex.Replace(findString, @"\", @"\\"); 
         } 

         //perform replace in new string 
         if (MainWindow.Main.chkIgnoreCase.IsChecked != null && (bool) MainWindow.Main.chkIgnoreCase.IsChecked)       
          newFileContent = Regex.Replace(fileContent, @findString, @replaceString, RegexOptions.IgnoreCase); 
         else 
          newFileContent = Regex.Replace(fileContent, @findString, @replaceString); 

         result[i].Result = true; 
         Globals.AppendTextToLine(string.Format(" success!")); 
        } 
        else 
        { 
         Globals.AppendTextToLine(string.Format(" failure!!")); 
         break; 
        } 
       } 
+0

Некоторые пищу для размышлений: Что делать, если положить файл в папке с размером, превышающим объем памяти, который у вас есть? В настоящее время ваше решение не удастся. Возможно, вам следует выполнять замену по очереди, а не по всему файлу сразу. –

+0

Позволяет пользователю вводить строку регулярных выражений, как правило, плохую идею, так как они могут легко стрелять в ногу. Исключением может быть инструмент dev, на котором пользователь должен знать, что это регулярное выражение заранее, и быть достаточно осведомленным, чтобы избежать их обратных косых черт. Неспециалист, выполняющий регулярное выражение, не является чем-то, что будет работать, и вам следует, вероятно, пересмотреть ваш подход. – McAden

+0

Приложите обратную связь, однако это инструмент поддержки для технической справочной службы. – Damo

ответ

2

Вы должны использовать Regex.Escape, когда вы передаете ввод пользователя в метод Replace.

Экранирует минимальный набор символов (\, *, +,, |?., {, [, (,), ^, $,, # и белое пространство), заменив их побега коды. Это инструктирует механизм регулярных выражений интерпретировать эти символы буквально, а не как метасимволы.

Например:

newFileContent = Regex.Replace(fileContent, 
           Regex.Escape(findString), 
           replaceString, 
           RegexOptions.IgnoreCase); 
+0

Из интереса - если вы избегаете особых символов, что делает Regex.Replace 'offer' над String.Replace? – tolanj

+0

@tolanj: Главное преимущество, которое сразу приходит в голову, заключается в том, что он позволяет выполнять поиск без учета регистра, передавая флаг 'RegexOptions.IgnoreCase'. – LukeH

+0

спасибо, я бы поклялся, что есть встроенная String.Replace, которая по крайней мере приняла StringComparison, но на самом деле нет. Кажется типичной ошибкой http://stackoverflow.com/questions/5549426/is-there- a-case-insensitive-string-replace-in-net-without-use-regex – tolanj

1

Ваш фундаментальный вопрос, что ваш позволяете своему пользователю ввести произвольное регулярное выражение и, таким образом, хорошо, его интерпретируется как регулярное выражение ...

либо вы целью является только, чтобы заменить литеральные строки, в каком случае использовать String.Replace ИЛИ вы хотите, чтобы позволить пользователю вводить регулярное выражение, и в этом случае просто примите, что пользователю нужно будет \ уклониться от своих специальных символов.

С \ является регулярное выражение побег символ (как и в C# один, но вы, кажется, иметь дело с тем, с @) «\» является незаконным регулярное выражение, потому что что вы спасаясь

Если вы Really хочет rexexp заменить все \ с \\, то его:

Regex.Replace(findString, @"\\", @"\\\\"); --ie one \ after escape, two chars after escape. 

Но у вас еще есть [] * и т.д., чтобы беспокоиться о.?.

Мой сильный совет флажок, пользователь может выбрать, если они вступают в регулярное выражение или строковый литерал для замены, а затем вызвать string.replace или Regex.Replace соответственно

+0

Хороший ответ, потому что вы охватываете оба findhString как регулярное выражение и литерал, но если его литеральные меташары должны быть экранированы (включает '' 'сам). +1 – sln

Смежные вопросы