You can use xparse, absorbing the whole contents and splitting it at \item; then add a semicolon (and the removed \item) between items.
The processing is complicated by the fact that a blank line between items would introduce a spurious paragraph before the semicolon or the final period, so we need to remove blanks and \par tokens at the end of each item.
Thus the sequence obtained by splitting at \item is mapped to “purify” it.
I added enumitem for maximum flexibility.
\documentclass{article} \usepackage{xparse} \usepackage{enumitem} \ExplSyntaxOn \NewDocumentEnvironment{autoitemize}{O{} +b} { \begin{itemize}[#1] \marcel_autoitemize:n { #2 } \end{itemize} }{} \seq_new:N \l__marcel_autoitemize_items_seq \seq_new:N \l__marcel_autoitemize_items_nopar_seq \tl_new:N \l__marcel_autoitemize_item_tl \cs_new_protected:Nn \marcel_autoitemize:n { % split the contents at \item; this also removes blanks at either end \seq_set_split:Nnn \l__marcel_autoitemize_items_seq { \item } { #1 } % remove the first (empty) item \seq_pop_left:NN \l__marcel_autoitemize_items_seq \l_tmpa_tl % we need to remove trailing \par tokens \seq_clear:N \l__marcel_autoitemize_items_nopar_seq \seq_map_function:NN \l__marcel_autoitemize_items_seq \__marcel_autoitemize_purify:n % start the first item \item % use the sequence, putting a semicolon and \item between items \seq_use:Nn \l__marcel_autoitemize_items_nopar_seq { ; \item } % end up with a period . } \cs_new_protected:Nn \__marcel_autoitemize_purify:n { \tl_set:Nn \l__marcel_autoitemize_item_tl { #1 } \regex_replace_once:nnN { \s* \c{par}* \Z } { } \l__marcel_autoitemize_item_tl \seq_put_right:NV \l__marcel_autoitemize_items_nopar_seq \l__marcel_autoitemize_item_tl } \ExplSyntaxOff \begin{document} \begin{autoitemize} \item One \item Two \item Three \end{autoitemize} \begin{autoitemize}[label=--] \item One \item Two \item Three \end{autoitemize} \end{document}
