CSS, 132 116 115 bytes
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 "
O CSS não é visto com muita frequência no código golf porque ele pode apenas formatar texto, mas na verdade funciona para esse desafio e achei que seria divertido fazer isso. Veja-o em ação usando o snippet acima (clique em "Mostrar snippet de código").
A lista deve estar em um arquivo HTML vinculado com cada elemento cercado por <a>
tags e separado por quebras de linha. Os itens da lista devem ser os únicos elementos em seu elemento pai, por exemplo
<a>one</a>
<a>two</a>
<a>three</a>
Explicação
a:not(:last-child):nth-child(n+2)::after,
a:nth-last-child(n+3)::after {
content: ",";
}
a + :last-child::before {
content: "and ";
}
Vamos considerar a versão não destruída acima. Se você não estiver familiarizado com o funcionamento do CSS, tudo fora dos chavetas é um seletor que determina o conjunto de elementos HTML aos quais as declarações dentro dos chavetas se aplicam. Cada par de seletor-declaração é chamado de regra . (É mais complicado que isso, mas será suficiente para esta explicação.) Antes de aplicar qualquer estilo, a lista aparece separada apenas por espaços.
Queremos adicionar vírgulas após cada palavra, exceto a última, exceto as listas de duas palavras, que não possuem vírgulas. O primeiro seletor,, a:not(:last-child):nth-child(n+2):after
seleciona todos os elementos, exceto o primeiro e o último. :nth-child(n+2)
é uma maneira mais curta de dizer :not(:first-child)
, e basicamente funciona selecionando elementos cujo índice (começando em 1) é maior ou igual a 2. (Sim, ainda me confunde um pouco. Os documentos do MDN podem ajudar.)
Agora só precisamos selecionar o primeiro elemento para obter uma vírgula se houver três ou mais elementos no total. a:nth-last-child(n+3):after
funciona como :nth-child
, mas contando pela parte de trás, por isso seleciona todos os elementos, exceto os dois últimos. A vírgula aceita a união dos dois conjuntos e usamos o :after
pseudoelemento para adicionar content
imediatamente após cada elemento selecionado.
A segunda regra é mais fácil. Precisamos adicionar "e" antes do último elemento da lista, a menos que seja um único elemento. Em outras palavras, precisamos selecionar o último elemento que é precedido por outro elemento. +
é o seletor de irmão adjacente em CSS.