Удалить одиночные разрывы строк, оставить пустые строки

Скажем, у меня есть текст, подобный следующему тексту, выделенному курсором:

This is a test. 
This 
is a test.

This is a test. 
This is a 
test.

Я хотел бы преобразовать его в:

This is a test. This is a test

This is a test. This is a test

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

Я думал, что что-то вроде следующего будет работать:

RemoveSingleLineBreaks()
{
  ClipSaved := ClipboardAll
  Clipboard =
  send ^c
  Clipboard := RegExReplace(Clipboard, "([^(\R)])(\R)([^(\R)])", "$1$3")    
  send ^v
  Clipboard := ClipSaved
  ClipSaved = 
}

Но это не так. Если я применю его к тексту выше, получится:

This is a test. This is a test.
This is a test. This is a test.

который также удалил «пустую строку» посередине. Это не то, чего я хочу.

Для пояснения: под пустой строкой я подразумеваю любую строку с "белыми" символами (например, табуляцией или пробелами).

Любые мысли, как это сделать?


person Amelio Vazquez-Reina    schedule 05.05.2012    source источник


Ответы (3)


RegExReplace(Clipboard, "([^\r\n])\R(?=[^\r\n])", "$1$2")

Это удалит одиночные разрывы строк, предполагая, что токен новой строки содержит либо CR, либо LF в конце (например, CR, LF, CR+LF, LF+CR). Он не считает пробелы пустыми.

Вашей основной проблемой было использование \R:

\R внутри класса символов — это просто буква «R» [source ]

Решение состоит в том, чтобы использовать символы CR и LF напрямую.


Чтобы уточнить: под пустой строкой я подразумеваю любую строку с «белыми» символами (например, вкладки или пробелы).

RegExReplace(Clipboard, "(\S.*?)\R(?=.*?\S)", "$1")

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

Предварительный просмотр используется, чтобы избежать «съедания» (сопоставления) следующего символа, который может разбиваться на односимвольных строках. Обратите внимание, что, поскольку он не соответствует, он не заменяется, и мы можем исключить его из строки замены. Смотреть назад нельзя, потому что PCRE не поддерживает просмотр назад переменной длины, поэтому вместо этого используются обычная группа захвата и обратная ссылка.


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

Если вы хотите заменить разрыв строки пробелами, это более уместно:

RegExReplace(Clipboard, "(\S.*?)\R(?=.*?\S)", "$1 ")

Это заменит одиночные разрывы строк пробелом.


И если вы хотите использовать просмотр назад и вперед:


Удалить одиночные разрывы строк:

RegExReplace(Clipboard, "(?<=[^\r\n\t ][^\r\n])\R(?=[^\r\n][^\r\n\t ])", "")


Замените одиночные разрывы строк пробелами:

RegExReplace(Clipboard, "(?<=[^\r\n\t ][^\r\n])\R(?=[^\r\n][^\r\n\t ])", " ")

По какой-то причине \S не работает при просмотре назад и просмотре вперед. По крайней мере, не с моим тестированием.

person Bob    schedule 09.06.2012
comment
Я хотел бы как проголосовать, так и проголосовать: довольно полезно, но ([^\r\n])\R([^\r\n]) и (\S.*?)\R(.*?\S) не работают для соединения строк с одним символом (без разрыва строки). Например. эта строка в нотации Java: "aaa\n" + "b\n" + "ccc" неправильно преобразуется в "aaab\nccc". Кроме того, я не совсем понимаю объяснение (\S.*?)\R(.*?\S) — не могли бы вы его расширить? - person Jan Żankowski; 07.03.2019
comment
@JanŻankowski ... вау, это было 7 лет назад. Отредактировано и исправлено для случая с одним символом с помощью просмотра вперед. Подробные пояснения по регулярному выражению см. в кратком справочнике по AHK и различных PCRE учебные пособия / объяснения доступны в Интернете. regular-expressions.info — хороший вариант. Или используйте инструмент, который может анализировать/объяснять синтаксис регулярных выражений, например. см. правую часть этой страницы regex101. - person Bob; 08.03.2019
comment
Спасибо, что быстро вернулись к этому после столь долгого времени! Здорово видеть, что взгляд вперед - это путь - я тоже так думал. Несколько замечаний: (1) первое регулярное выражение ([^\r\n])\R([^\r\n]), вероятно, тоже нуждается в предварительном просмотре, (2) после возни с (\S.*?)\R(?=.*?\S) в тестере регулярных выражений, который вы любезно предложили, я не думаю, что нежадные модификаторы (? в *?) необходимы - group и lookahead будут иметь более широкие совпадения в строке до и в строке после разрыва строки, но тоже будут работать — и читаются проще. - person Jan Żankowski; 08.03.2019
comment
@JanŻankowski Правда, я подумал об этом сегодня днем. Я думаю, что изначально я не был уверен в поведении . при сопоставлении разрывов строк, поэтому было некоторое опасение, что жадный может соответствовать большему количеству, чем предполагалось. Тем не менее, теоретически нежадный код должен быть быстрее, потому что он остановится раньше, но отсутствие ретроспективного просмотра переменной длины означает, что нежадный и жадный варианты эквивалентны. Отредактировал первый пример, оставив пока не жадных. - person Bob; 08.03.2019

Я верю, что это сработает:

text=
(
This is a test. 
This 
is a test.

This is a test. 
This is a 
test.
)
MsgBox %    RegExReplace(text,"\S\K\v(?=\S)",A_Space)
person SouthStExit    schedule 04.06.2012

person    schedule
comment
Когда я запускаю это, скрипт удаляет текст (т.е. Clipboard присваивается пустая строка) - person Amelio Vazquez-Reina; 06.05.2012
comment
да... решение неверное, не обращайте на него внимания. В нем была скобка несоответствия, но это было не так. Проблема заключалась в том, что перед концом строки могут быть пустые места. У меня тоже проблемы с реализацией этого только с регулярным выражением :) - person mihai; 06.05.2012