Регулярное выражение заменяет, но только между двумя шаблонами

StackOverflow https://stackoverflow.com/questions/608319

  •  03-07-2019
  •  | 
  •  

Вопрос

Хорошо, у меня есть многострочная строка, над которой я пытаюсь произвести некоторую очистку.

Каждая строка может быть, а может и не быть частью большого блока текста, заключенного в кавычки.Пример:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted
and so is this one
and so is this one.”
This is not quoted “but this is
and so is this.”

Мне нужна замена регулярного выражения, которая отменит перенос строк с жесткими кавычками, т. е. заменит " \ n" пробелом, но только между фигурными кавычками.

Вот как это должно выглядеть после замены:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted and so is this one and so is this one.”
This is not quoted “but this is and so is this.”

(Обратите внимание, что последние две строки были несколькими строками входного текста.)

Ограничения

  • В идеале нужен один вызов замены регулярного выражения
  • Использование библиотеки регулярных выражений .NET
  • Цитаты следующие всегда начинайте / заканчивайте фигурные кавычки, а не обычные двойные галочки ("), что должно немного упростить задачу.

Важное ограничение

Это не прямое.ЧИСТЫЙ код, я заполняю таблицу строками "searchfor / replacewith", которые затем вызываются через RegEx.Replace.У меня нет возможности добавлять пользовательский код, такой как средства оценки соответствия, перебор захваченных групп и т.д.

Текущий ответ на данный момент, что-то вроде:

r.Replace("(?<=“)\r\n(?=”)", " ")

Очевидно, я еще даже не приблизился к этому.

Та же логика может быть применена, скажем, к цветовому кодированию блочных комментариев в программном коде - все, что находится внутри блочного комментария, обрабатывается не так, как материал вне комментариев.(Код немного сложнее, поскольку разделители комментариев начального / конечного блока также могут законно существовать внутри литеральной строки, с чем мне здесь не приходится сталкиваться.)

Это было полезно?

Решение

Предполагая, что все фигурные кавычки правильно сбалансированы, это регулярное выражение должно делать то, что вы хотите:

@"[\r\n]+(?=[^“”]*”)"

Тот Самый [\r\n]+ будет соответствовать одному или нескольким разделителям строк любого типа - Unix ( ), DOS ( ) или более старому Mac ( ).Затем прогноз утверждает, что впереди есть закрытая кавычка и что между здесь и там нет открытой кавычки.Тогда ваш заменяющий текст может быть простым символом пробела.

Другие советы

Примечание:Для тестирования регулярных выражений я использую http://gskinner.com/RegExr/ что очень полезно.

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

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

(?s)

Затем вы хотите, чтобы внешнее выражение соответствовало начальной цитате:

(?<=“)

И заглядывание вперед, чтобы соответствовать конечной цитате:

(?=”)

Теперь выражение, соответствующее некоторому тексту, затем перевод строки, затем некоторый текст:

([^”\r]*)\r?([^”\r]*)

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

(?s)(?<=“)([^”\r]*)\r?([^”\r]*)\r?([^”\r]*)(?=”)

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

Оставьте свое выражение примерно таким:

r.Replace("(?s)(?<=“)([^”\r]*)\r?([^”\r]*)", "$1 $2")

(Это не совсем корректно, поскольку после текста будет добавлен пробел, даже если вторая группа не совпадает...но это только начало)

Итак, что нужно сделать, это найти строку, начинающуюся с открывающей кавычки, за которой следует строка, которая делает нет содержит заключительную кавычку или любые символы \ n, за которыми следует серия из одного или нескольких символов \ r \ n, захватывает все, кроме символов терминала \ r \ n, и заменяет полное совпадение захваченной частью.

-- МаркусК

Я думаю, что самым простым способом было бы сопоставить приведенные в кавычках разделы с “(?s:.*?)” и использовать Вычислитель соответствия чтобы удалить все новые строки.Код MatchEvaluator может быть таким же простым, как

Replace(@"\s+", " ");

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

Вы не можете делать то, что хотите, в тех пределах, которые вы описали.

Доказательство:

  • Ваша фиксированная таблица замен будет выполнять фиксированное количество вызовов для замены (назовите это n)
  • Каждая замена сможет устранить только фиксированное количество разрывов строк (назовите это число m).

Следовательно

  • Заключенный в кавычки блок с m * n + 1 разрывами строк не будет обработан должным образом.

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

-- МаркусК

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top