CSS, 132 116 115 байт
a:not(:last-child):nth-child(n+2):after,a:nth-last-child(n+3):after{content:","}a+:last-child:before{content:"and "
<p>
<a>one</a>
</p>
<p>
<a>one</a>
<a>two</a>
</p>
<p>
<a>one</a>
<a>two</a>
<a>three</a>
</p>
<p>
<a>one</a>
<a>two</a>
<a>three</a>
<a>four</a>
</p>
a:not(:last-child):nth-child(n+2):after,a:nth-last-child(n+3):after{content:","}a+:last-child:before{content:"and "
CSS не часто встречается в гольф-коде, потому что он может только форматировать текст, но на самом деле он работает для этой задачи, и я подумал, что это будет интересно. Посмотрите его в действии, используя приведенный выше фрагмент (нажмите «Показать фрагмент кода»).
Список должен быть в связанном HTML-файле, где каждый элемент окружен <a>
тегами и разделен переносами строк. Элементы списка должны быть единственными элементами в их родительском элементе, например
<a>one</a>
<a>two</a>
<a>three</a>
объяснение
a:not(:last-child):nth-child(n+2)::after,
a:nth-last-child(n+3)::after {
content: ",";
}
a + :last-child::before {
content: "and ";
}
Давайте рассмотрим вышедшую из строя версию выше. Если вы не знакомы с тем, как работает CSS, все, что находится вне фигурных скобок, является селектором, который определяет набор элементов HTML, к которым применяются объявления внутри фигурных скобок. Каждая пара объявление-селектор называется правилом . (Это более сложно, но этого будет достаточно для этого объяснения.) Перед применением какого-либо стиля, список кажется разделенным только пробелами.
Мы хотим добавлять запятые после каждого слова, кроме последнего, за исключением списков из двух слов, которые не имеют запятых. Первый селектор, a:not(:last-child):nth-child(n+2):after
выбирает все элементы, кроме первого и последнего. :nth-child(n+2)
это более короткий способ сказать :not(:first-child)
, и он в основном работает, выбирая элементы, индекс которых (начиная с 1) больше или равен 2. (Да, это все еще немного смущает меня. Документы MDN могут помочь.)
Теперь нам просто нужно выбрать первый элемент, чтобы получить запятую, если всего три или более элементов. a:nth-last-child(n+3):after
работает как :nth-child
, но с обратной стороны, поэтому он выбирает все элементы, кроме двух последних. Запятая принимает объединение двух наборов, и мы используем :after
псевдоэлемент для добавления content
сразу после каждого выбранного элемента.
Второе правило проще. Нам нужно добавить «и» перед последним элементом в списке, если это не единственный элемент. Другими словами, нам нужно выбрать последний элемент, которому предшествует другой элемент. +
это соседний селектор в CSS.