Retina, 45 43 bytes
Byte count assumes ISO 8859-1 encoding.
O$#`.(?<=(.+))|¶
$.1
!`(?<=(¶)+.*)(?<-1>.)+
The leading linefeed is significant. Input and output are linefeed-terminated lists of printable ASCII strings (note that both have a single trailing linefeed).
Try it online!
I knew for a while that transposing rectangular blocks would be a pain in Retina (whereas transposing squares isn't too bad), but never actually tried. The first solution was indeed a whopping 110 bytes long, but after several substantial changes in the approach, the resulting 45 bytes are by far not as bad as I suspected (but still...). Explanation will follow tomorrow.
Explanation
Stage 1: Sort
O$#`.(?<=(.+))|¶
$.1
This does the main work of reordering the characters in the input, but it ends up messing up the separation into lines. Interestingly, if we remove the |¶, we get the code required to transpose a square input.
Этапы сортировки (обозначенные как O) работают следующим образом: они находят все совпадения заданного регулярного выражения (вещь после `), а затем сортируют эти совпадения и повторно вставляют их в места, где были найдены совпадения. Как это происходит, это регулярное выражение соответствует каждому отдельному символу: не-переводы строк через .(?<=(.*))альтернативу и переводы строк через ¶. Следовательно, он сортирует все символы на входе. Более интересная часть это то , что они сортируются по .
$Опция активирует «сортировки по» режиме, где каждый матч заменяется с шаблоном подстановки на второй линии, которая затем используется для сравнения совпадений. Кроме того, #велит Retina преобразовать результат подстановки в целое число и сравнить эти целые числа (вместо того, чтобы рассматривать их как строки).
Итак, наконец, нам нужно взглянуть на регулярное выражение и замену. Если первая альтернатива соответствует (то есть мы сопоставили любой символ в одной из строк), то (?<=(.*))захват захватывает все, вплоть до этого символа в этой строке, в группу 1. $.1В схеме замещения замещает это с длиной группы 1. Следовательно, первый символ в каждой строке становится 1, второй становится 2, третий становится 3и так далее. Теперь должно быть понятно, как это транспонирует квадратные входные данные: все первые символы строк идут первыми и все заканчиваются в самой верхней строке, затем все вторые символы заканчиваются во второй строке и так далее. Но для этих прямоугольных входов мы также подбираем перевод строки. С группой1 неиспользованным в этом случае, подстановка пуста, но для целей #опции это рассматривается 0. Это означает, что все переводы строки отсортированы на передний план.
Итак, теперь у нас есть символы первого порядка (первый символ каждой строки, второй символ каждой строки и т. Д.) И все переводы строк в начале.
Этап 2: Матч
!`(?<=(¶)+.*)(?<-1>.)+
Теперь нам нужно разделить символы на строки правильной длины. Эта длина соответствует количеству строк в исходном вводе, что соответствует количеству перевода строки, которое мы имеем в начале строки.
Разделение выполняется здесь с помощью этапа сопоставления, который просто находит все совпадения данного регулярного выражения и использует ! опцию для печати этих совпадений (по умолчанию вместо этого будет их подсчитываться). Таким образом, цель регулярного выражения - соответствовать одной строке за раз.
Мы начнем с «подсчета» числа со взглядом сзади (?<=(¶)*.*). Генерирует один захват в группе1 для каждого перевода строки на фронте.
Затем для каждого из этих снимков мы сопоставляем одного символа с (?<-1>.)+.