This is extensible by adding character translations. It uses the standard array environment.
The idea is to change an input such as |bo|x| into
\multicolumn{1}{|c}{\__fukai_mymacro_char:n{b}} &
\multicolumn{1}{c|}{\__fukai_mymacro_char:n{o}} &
\multicolumn{1}{c|}{\__fukai_mymacro_char:n{x}}
where the last function translates b into a phantom, just to be sure it occupies the same space as the other characters, o into \bigcirc and x into \bigotimes.
The search regular expression means: find zero or one occurrences of | followed by a letter and zero or one occurrences of |. This is replaced by \multicolumn as shown above. At the end of this multiple replacement we need to remove an unwanted trailing &.
The number of columns is computed by examining the arguments and passing +1 for anything that's not |.
\documentclass{article}
\usepackage{array}
\ExplSyntaxOn
\NewDocumentCommand{\mymacro}{mm}
{
\fukai_mymacro:nn { #1 } { #2 }
}
\tl_new:N \l__fukai_mymacro_a_tl
\tl_new:N \l__fukai_mymacro_b_tl
\cs_new_protected:Nn \fukai_mymacro:nn
{
% normalize the input
__fukai_mymacro_normalize:Nn \l__fukai_mymacro_a_tl { #1 }
__fukai_mymacro_normalize:Nn \l__fukai_mymacro_b_tl { #2 }
% start the array with the suitable number of columns
\begin{array}
{
* { \int_max:nn { __fukai_mymacro_count:n { #1 } } { __fukai_mymacro_count:n { #1 } } } { c }
}
\tl_use:N \l__fukai_mymacro_a_tl
\ \hline
\tl_use:N \l__fukai_mymacro_b_tl
\end{array}
}
\cs_new_protected:Nn __fukai_mymacro_normalize:Nn
{
\tl_set:Nn #1 { #2 }
\regex_replace_all:nnN
{ (|)??([[:alpha:]])(|?) } % |<char>|
{ \c{multicolumn}{1}{\1 c \3}{ \c{__fukai_mymacro_char:n}{\2} } & }
#1
\regex_replace_once:nnN { & \Z } { } #1
}
% count the non-| characters
\cs_new:Nn __fukai_mymacro_count:n
{
\int_eval:n { 0 + \str_map_function:nN { #1 } __fukai_mymacro_ischar:n }
}
\cs_new:Nn __fukai_mymacro_ischar:n
{
\str_if_eq:nnF { #1 } { | } { +1 }
}
% the translations
\cs_new:Nn __fukai_mymacro_char:n
{
\str_case:nn { #1 }
{
{b}{\phantom{\bigcirc}}
{o}{\bigcirc}
{x}{\bigotimes}
}
}
\ExplSyntaxOff
\begin{document}
$\mymacro{|b|b|ooo|x|}{oooooo}$
\bigskip
$\mymacro{|bo|x|}{o|x|b}$
\bigskip
$
\begin{array}{ccc}
\multicolumn{1}{|c}{} & \multicolumn{1}{c|}{\bigcirc} & \multicolumn{1}{c|}{\bigotimes}
\\hline
\multicolumn{1}{c|}{\bigcirc} & \multicolumn{1}{c|}{\bigotimes} & \multicolumn{1}{c}{}
\end{array}
$
\end{document}
In the image, the third array is “hand made” to show the result is the same as with the second array done with \mymacro.
