Regex: заменить произвольное количество пробелов тем же номером другого символа

759
AntumDeluge

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

В частности, я хочу взять такой список:

foo url1 foobar url2 foo bar url3 

И преобразовать это в это:

foo ...... url1 foobar ... url2 foo bar .. url3 

Я использую Eclipse IDE для редактирования моего текста. Я не знаком с различными движками регулярных выражений, но я предполагаю, что он использует либо Jakarta Regexp, либо java.util.regex (который я посмотрел в Википедии).

Я могу захватить пробельные символы в поле « Поиск», используя « ( +)», но я не знаю, как преобразовать их в такое же количество точек в поле « Заменить на» .

Я немного погуглил и наткнулся на этот вопрос (вот где я выучил ( +)синтаксис " "). Похоже, что это может быть то же самое, или похожий на мой вопрос. Но я либо не нашел свой ответ, либо просто не понял ответы.

0
Есть пробелы или просто пробелы? Ваше выражение, кажется, только о пробелах. Тогда почему бы просто не заменить пробел любым другим персонажем, который вам нравится? sticky bit 6 лет назад 0
Потому что они не хотят менять пробелы в заголовке; например, «foo bar» → «foo.bar». Кроме того, они не хотят менять «foo url» на «foo ........ url»; они хотят «foo␣ ...... ␣url» (сохраняя первый и последний пробел). Scott 6 лет назад 0
@ Скотт Правильно. AntumDeluge 6 лет назад 0
Это звучит как вопрос, который задавался ранее, и, вполне возможно, на него уже был дан ответ здесь или на [Unix & Linux Stack Exchange] (https://unix.stackexchange.com). Но я не помню ответ прямо сейчас. Я постараюсь вернуться к этому позже, когда у меня будет больше времени, но до тех пор я предлагаю вам поискать наш сайт немного сложнее. Подсказка: [SE] имеет свою собственную поисковую систему, но иногда вы получаете лучшие результаты, используя Google и говоря `` `site: superuser.com``` или` `` site: unix.stackexchange.com```. Scott 6 лет назад 0
Я провел краткий поиск (около 15 минут) и не нашел точных совпадений, хотя [Использование sed для замены всех вхождений в начале на соответствующее количество замещающих строк] (https://unix.stackexchange.com/ q / 433513/23408) и [Заменить символы в соответствующей строке] (https://unix.stackexchange.com/q/352502/23408) близки. Поскольку никто не пометил ваш вопрос как дубликат, и вы до сих пор получили только один ответ, я сам изобрел три ответа (первый очень похож на один из вопросов, на которые я ссылался). Я надеюсь, что у вас есть доступ к `sed`. Scott 6 лет назад 0

2 ответа на вопрос

1
Toto

Вы можете сделать это с помощью Notepad ++

  • Ctrl+H
  • Найти то, что: (?<!\S) (?= )
  • Заменить: .
  • проверить обернуть
  • проверьте регулярное выражение
  • Replace all

Объяснение:

(?<! : Start negative lookbehind, make sure we have not \S : a non-space character ) : end lookbehind : a space (?= : start lookahead, make sure we have : a space ) : en lookahead 

Замена:

. : a dot 

Результат для данного примера:

foo ...... url1 foobar ... url2 foo bar .. url3 
Выглядит интересно. У меня нет Notepad ++, поэтому я не могу это проверить. Можете ли вы объяснить, почему это не заменяет первый пробел после заголовка, что приводит к `` foo ....... ␣url1``? Scott 6 лет назад 0
@ Скотт: Я уверен, что он также работает с SublimeText. Пробел заменяется только тогда, когда перед ним нет пробела, а после - пробел. Toto 6 лет назад 0
Ох ... когда есть пробел после, и *** не **, ** не *** пробел до. Я пропустил двойной негатив. Не могли бы вы просто сделать регулярный взгляд за пробел вместо негативного за не пробел? Scott 6 лет назад 0
@Scott: Нет, если я использую положительный вид сзади (т. Е. `(? <= \ S)`), пробел перед обязательным, * a contrario * `(? Toto 6 лет назад 0
Ну, я все еще не понимаю. :-( ⁠ Scott 6 лет назад 0
@ Скотт: Это нелегко объяснить, но попробуйте оба выражения, и тогда все станет ясно. Toto 6 лет назад 0
0
Scott

Вопрос явно гласит, что заголовки будут содержать пробелы. В целях безопасности я предполагаю, что заголовки могут содержать точки (точки); например, «История 3.14159» или «Доктор Открытие Дулиттла ». Мои ответы предполагают, что есть какой-то символ, который никогда не появится в оглавлении; в частности, они предполагают, что это так @. Если у вас есть @в таблице, замените его на какой - то символ, который никогда не появляется (например, #, ^, _, |и т.д.). Если вы действительно используете каждый символ ASCII, вам может потребоваться использовать последовательность символов, например <@>.

Три способа сделать это с sed:

Loop:

sed 's/\(.*\)\( \)/\1@\2/; :loop; s/ @/ @./; t loop; s/@//' 
  • s/\(.*\)\( \)/\1@\2/находит последний пробел в строке и вставляет @перед ним.
  • :loop это метка, как маркер мили.
  • s/ @/ @./(то есть s/␣␣@/␣@./для не двусмысленности) говорит, что если есть два пробела перед @, замените их на ␣.(пробел и точка) и переместите @между ними.
  • t loopговорит, что если вышеуказанная замена прошла успешно, вернитесь к :loopмаркеру и повторите. В противном случае продолжайте
  • s/@//, который удаляет @.

Поэтому foo barстрока в вашей таблице будет обработана следующим образом:

Начальное значение: foo bar url3 s / \ (. * \) \ (\) / \ 1 @ \ 2 / foo bar @ url3 s / @ / @. / foo bar @. url3 s / @ / @. / foo bar @ .. url3 s / @ / @. / foo bar @ .. url3 (Подстановка не удалась, поэтому не зацикливайтесь) s / @ // foo bar .. url3 Конечный результат: foo bar .. url3

Подавляющие цифры:

sed 's/\(.*\)\( \)/\1@@@@@@@@@@@@@@@@@@@@\2/; s/ [ @]\/ /; s/@/./g' 
  • s/\(.*\)\( \)/\1@@@@@@@@@@@@@@@@@@@@\2/ очень похоже на первую sподкоманду в первом решении; он находит последний пробел в строке и вставляет перед ним строку из 20 @символов. На самом деле это должно быть число, по крайней мере равное максимальному количеству точек, которое вам когда-либо понадобится вставить в одну строку; например, 80. Управление строкой из 80 @символов было бы неудобно; вы можете заменить это
    • s/\(.*\)\( \)/\1<@><@><@><@><@>\2/; s/<@>/@@@@@@@@/g который вставляет строку из пяти <@>последовательностей, а затем заменяет каждую из них строкой из 16 @символов, в результате чего получается 5 × 16 = 80 @символов.
  • s/ [ @]\/ /находит строку из 20 последовательных символов, которые являются либо пробелом, либо пробелом @, которому предшествует пробел, и заменяет его только предыдущим пробелом. Замените 20на число из предыдущего шага.
  • s/@/./gзаменяет все оставшиеся @точки.

Поэтому fooстрока в вашей таблице будет обработана следующим образом:

Initial value: foo url1 s/\(.*\)\( \)/\1@@@@...@@@@\2/ foo @@@@@@@@@@@@@@@@@@@@ url1 s/ [ @]\/ / _[↑↑↑↑↑↑remove↑↑↑↑↑↑] foo @@@@@@ url1 s/@/./g foo ...... url1 

Используйте «место для удержания»:

sed 's/.*[^ ] /&@/; h; s/ /./g; s/\(\.*\)\./\1 /; x; G; s/@.*@//' 
  • s/.*[^ ] /&@/это похоже на предыдущие команды; он находит конец заголовка - если быть точным, последнее место, где непустой символ сопровождается пробелом - и вставляет @после него.
  • h копирует строку в область удержания.
  • s/ /./g заменяет все пробелы в строке точками.
  • s/\(\.*\)\./\1 /заменяет последнюю точку пробелом (Это нужно будет изменить, если URL может содержать точки, что, я думаю, вероятно.)
  • x обменивает пространство образца и пространство удержания.
  • Gдобавляет пространство удержания к пространству шаблона. Теперь у нас есть, по сути, две копии строки.
  • s/@.*@// сохраняет первую часть первой копии и вторую часть второй копии, избавляясь от содержимого в середине.
Initial value: foo bar url3  Pattern space Hold space s/.*[^ ] /&@/ foo bar @ url3 h foo bar @ url3 foo bar @ url3 s/ /./g foo.bar.@...url3 foo bar @ url3 s/\(\.*\)\./\1 / foo.bar.@.. url3 foo bar @ url3 x foo bar @ url3 foo.bar.@.. url3 G foo bar @ url3 foo.bar.@.. url3 foo.bar.@.. url3 s/@.*@// foo bar .. url3 foo.bar.@.. url3  Final output: foo bar .. url3 

Похожие вопросы