Что нового

[RegExp] Замена N-ое кол-ство символов пробела на N-ое кол-ство " "

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Итак, нужно в строке заменить несколько идущих подряд символов пробела (хотя по идее оно было бы полезно для любых символов), на такое же количество их аналога в html -

Пример строки:
Код:
some data
    		MsgBox(64, 'Title', 'Text')
          ConsoleWrite("test" & @LF)
some data

на выходе нужно получить это:
Код:
some data
      MsgBox(64, 'Title', 'Text')
          ConsoleWrite("test" & @LF)
some data

Всё что у меня получилось, так это циклом заменять пока это доступно:

Код:
$sData = _
	'some data' & @CRLF & _
	'    		MsgBox(64, "Title", "Text")' & @CRLF & _
	'          ConsoleWrite("test" & @LF)' & @CRLF & _
	'some data'

While 1
	$sData = StringRegExpReplace($sData, '(?m)^(( )*)?\s', '\1 ')
	If @extended = 0 Then ExitLoop
WEnd

ConsoleWrite($sData & @LF)


Хотелось бы это организовать одной строкой, в целях ускорения замены.
 

amel27

Продвинутый
Сообщения
146
Репутация
55
одной строкой никак, по ряду причин:

- для посимвольной замены требуется проверка положения "пробела" по отношению к началу текущей строки (ретроспективная проверка), но в PCRE она не поддерживает шаблоны переменной длины: * + ? и т.п. (в отличие от опережающей проверки), т.е. придется перебирать все возможные комбинации '^|^ |^ |...', а это не вариант, т.к. громоздко и медленно;
- для замены подстроками требуется длина заменяемой подстроки "пробелов", но StringRegExpReplace таких данных не предоставляет

самое короткое, что получилось (не факт, что самое быстрое) в два прохода:

Код:
$sData = StringRegExpReplace($sData, '(?m)^[ \t]([ \t]*+)', '\1'& Chr(0))
$sData = StringRegExpReplace($sData, '(?=[ \t]*+\x0).', ' ')
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
amel27 [?]
самое короткое, что получилось (не факт, что самое быстрое) в два прохода
Отлично, но хотелось бы ещё внести уточнение...
Символы пробела могут содержать как сам прбел, так и символ табуляции, и самое главное - они могут быть преремешаны, и при чём заменять нужно пробел на одну , а табуляцию на 4 таких заменителя.

Следующая строка содержит подобные пробелы:
Код:
  			  		ConsoleWrite("test" & @LF)
нужно получить из неё 24 пробела (чтобы повторялась столько раз).

У меня получилось в 4 захода:
Код:
$sData = '  			  		ConsoleWrite("test" & @LF)'

; Получаем все ведущие символы пробела и табуляции 
$sSpaces = StringRegExpReplace($sData, '(?m)^(\s+).*', '\1')

; Заменяем в полученной строке символов пробела и табуляции все *символы пробела* на *один* экземпляр ' '
$sSpaces = StringReplace($sSpaces, ' ', ' ')
$iExtended = @extended ; Задаём счётчик замены

; Заменяем в полученной строке символов пробела и табуляции все *символы табуляции* на *4* экземпляра ' '
$sSpaces = StringReplace($sSpaces, @TAB, '    ')
$iExtended += (@extended * 4) ; Увеличиваем счётчик замены

; Ну и наконец заменяем в оригинальной строке *ЛЮБЫЕ* символы пробела на сформатированную раннее нами строку с ' '
$sData = StringRegExpReplace($sData, '(?m)^\s+(.*)', $sSpaces & '\1')

ConsoleWrite($iExtended & @LF & $sData & @LF)
 

El Panda

Продвинутый
Сообщения
101
Репутация
59
Эммм. Немного оффтоп, но всетаки, что мешает использовать тег pre или в крайнем случае стили?

Код:
<pre>
some data
          MsgBox(64, 'Title', 'Text')
          ConsoleWrite("test" & @LF)
some data
</pre>
 

amel27

Продвинутый
Сообщения
146
Репутация
55
CreatoR сказал(а):
Символы пробела могут содержать как сам прбел, так и символ табуляции, и самое главное - они могут быть преремешаны, и при чём заменять нужно пробел на одну , а табуляцию на 4 таких заменителя.
учитывая, что StringRegExpReplace не поддерживает условных замен, то потребуется как минимум один служебный и два рабочих прохода:

Код:
$s = StringRegExpReplace($s,'(?m)^[ \t]([ \t]*+)','\1'&Chr(0)) ; маркировка целевых подстрок
$s = StringRegExpReplace($s,'(?=\t[ \t]*+\x0).','    ')        ; обработка табуляторов
$s = StringRegExpReplace($s,'(?= *+\x0).',' ')            ; обработка пробелов


CreatoR сказал(а):
У меня получилось в 4 захода
так ведь это только для однострочного текста... :-\

CreatoR сказал(а):
хотелось бы ещё внести уточнение...
дык и я о том же - обсуждение постановки задачи может занять больше места, чем самого алгоритма... ;)
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
El Panda [?]
что мешает использовать тег pre или в крайнем случае стили?
Этот тег в IE делает странные вещи при опредлелённых стилях. Но даже если и можно заставить пробелы отображаться как положенно, мне всё ровно было интересно как делать подобные замены.

amel27 [?]
так ведь это только для однострочного текста...
Ну да, у меня это делается в цикле, я просто не хотел рисковать с заменой по всей строке.

Спасибо за пример, то что нужно.
 
Верх