Сітківка , 108 102 94 87 82 64 63 байт
Завдяки Sp3000 за те, що він змусив мене дотримуватися оригінального підходу, завдяки якому кількість байтів з 108 знизилася до 82.
Величезне спасибі Кобі, який знайшов набагато більш елегантне рішення, що дозволило мені зберегти ще 19 байтів.
S_`(?<=^(?<-1>.)*(?:(?<=\G(.)*).)+)
.
$0
m+`^(?=( *)\S.*\n\1)
<space>
Де <space>
представляє єдиний пробільний символ (який інакше був би позбавлений SE). Для підрахунку кожен рядок складається в окремому файлі і його \n
слід замінити фактичним символом подачі рядків. Для зручності можна запустити код як з одного файлу з -s
прапором.
Спробуйте в Інтернеті.
Пояснення
Ну ... як завжди, я не можу дати повного вступу до балансуючих груп тут. Для букваря дивіться мою відповідь на переповнення стека .
S_`(?<=^(?<-1>.)*(?:(?<=\G(.)*).)+)
Перший етап - це S
плітна стадія, яка розбиває вхід на лінії збільшення довжини. _
Вказує на те, що порожні шматки повинні бути виключені з розщеплення (яке впливає тільки на кінець, тому що там буде матч в останній позиції). Сам регулярний вираз повністю міститься в огляді, тому він не відповідає жодним символам, а лише позиціям.
Ця частина заснована на рішенні Кобі з деякою додатковою гольфізмом, яку я знайшов. Зауважте, що параметри виглядів узгоджені справа вліво в .NET, тому наступне пояснення найкраще читати знизу вгору. Я також вклав ще одне \G
в пояснення для ясності, хоча це не потрібно для роботи шаблону.
(?<=
^ # And we ensure that we can reach the beginning of the stack by doing so.
# The first time this is possible will be exactly when tri(m-1) == tri(n-1),
# i.e. when m == n. Exactly what we want!
(?<-1>.)* # Now we keep matching individual characters while popping from group <1>.
\G # We've now matched m characters, while pushing i-1 captures for each i
# between 1 and m, inclusive. That is, group <1> contains tri(m-1) captures.
(?:
(?<=
\G # The \G anchor matches at the position of the last match.
(.)* # ...push one capture onto group <1> for each character between here
# here and the last match.
) # Then we use a lookahead to...
. # In each iteration we match a single character.
)+ # This group matches all the characters up to the last match (or the beginning
# of the string). Call that number m.
) # If the previous match was at position tri(n-1) then we want this match
# to happen exactly n characters later.
Я все ще захоплююся роботою Кобі. Це навіть більш елегантно, ніж основний тестовий регекс. :)
Перейдемо до наступного етапу:
.
$0
Просто: вставляйте пробіл після кожного символу, який не передається в рядку.
m+`^(?=( *)\S.*\n\1)
<space>
На цьому останньому етапі відступають усі рядки правильно, щоб утворити трикутник. Це m
просто звичайний багаторядковий режим, щоб ^
зрівняти початок рядка. +
Каже Retina повторити цей етап , поки рядок не перестає змінюватися (що, в даному випадку означає , що регулярний вираз більше не відповідає).
^ # Match the beginning of a line.
(?= # A lookahead which checks if the matched line needs another space.
( *) # Capture the indent on the current line.
\S # Match a non-space character to ensure we've got the entire indent.
.*\n # Match the remainder of the line, as well as the linefeed.
\1 # Check that the next line has at least the same indent as this one.
)
Таким чином, це відповідає початку будь-якого рядка, який не має більшого відступу, ніж наступного. У будь-якому такому положенні ми вставляємо пробіл. Цей процес припиняється, як тільки лінії розташовані в акуратному трикутнику, оскільки це мінімальний макет, де кожен рядок має більший відступ, ніж наступний.