add tag
निरंजन
I want to have vertical lines around my table (or matrix), but only when needed. eg. If I use `|` in the argument of tabular, it places a vertical line fully on the column. `vline` doesn't come at the exact place where the regular vertical line comes. Using multi-column every time is cumbersome. Thus I need a simpler solution.

I want to automate the following style of matrix -

![IMG-20190121-WA0009.jpg](/image?hash=fa9acefd7e3c4853259698844faf8e615a7cc17e6dd4d5bad46fb0fcab6bbe7f)

After @JouleV's suggestion, I tried the following code with the help of TikZ matrix -

```
\documentclass[tikz,border=0.5cm]{standalone}
\usetikzlibrary{matrix,positioning,calc,decorations}
\usepackage{xparse}
\usepackage{environ}
\NewEnviron{antara}[1]{
\begin{tikzpicture}[transform shape]
\matrix (antara) [matrix of nodes,nodes={text width=2.5mm},ampersand replacement=\&]
{
\BODY
};
\foreach \x in {#1}
\draw (antara-1-\x.north west) -- (antara-2-\x.south west);
%\draw (antara.north west) -- (antara.south west);
%\draw (antara.north east) -- (antara.south east);
\draw node[below] at (antara-2-1.south) {$\times$};
\end{tikzpicture}
}

\begin{document}
    \begin{antara}{1,2,3}
        a \& b \& c\\
        d \& e \& f\\
    \end{antara}
\end{document}
```

The only difficulty is the lines are not of equal heights. 
Top Answer
Skillmon
The following provides two things. First a slightly patched `tabular` environment called `mytabular` in which the row number is accessible through the counter `\g__mytabular_current_row_int`.

Additionally a `\whimsicalrule` (credits to the lovely samcarter for the name) will be a vertical rule which takes an argument which will be a comma separated list of rows or row ranges in which the rule should occur.

The code for `mytabular` is most likely longer than necessary, but I already had it laying around in a package I didn't push to CTAN and only renamed a few macros.

*Ignore the fold marks `%>>=` and `%=<<`.*

```
\documentclass[]{article}

\usepackage{xparse}
\usepackage{array}
\usepackage{etoolbox}

\ExplSyntaxOn
\makeatletter
\NewDocumentCommand \whimsicalrule { m }%>>=
  {
    \exp_args:NV
    \tl_if_eq:nnTF \@currenvir { mytabular }
      { \whimsicalrule:n { #1 } }
      { \msg_error:nn { whimsicalrule } { not~in~mytabular } }
  }%=<<
\cs_new_protected:Npn \whimsicalrule:n #1 %>>=
  {
    \clist_map_inline:nn { #1 }
      {
        \tl_if_in:nnTF { ##1 } { - }
          { \whimsicalrule_in_range:w ##1 \q_stop }
          { \whimsicalrule_if_eq:n { ##1 } }
      }
  }%=<<
\cs_new_protected:Npn \whimsicalrule_in_range:w #1 - #2 \q_stop%>>=
  {
    \bool_lazy_and:nnT
      { \int_compare_p:nNn \g__mytabular_current_row_int > { #1 - \c_one_int } }
      { \int_compare_p:nNn \g__mytabular_current_row_int < { #2 + \c_one_int } }
      { \tex_vrule:D width \arrayrulewidth \relax }
  }%=<<
\cs_new_protected:Npn \whimsicalrule_if_eq:n #1%>>=
  {
    \int_compare:nNnT \g__mytabular_current_row_int = { #1 }
      { \tex_vrule:D width \arrayrulewidth \relax }
  }%=<<
\msg_new:nnn { whimsicalrule } { not~in~mytabular }%>>=
  { \string\whimsicalrule\space used~outside~of~`mytabular'~environment }%=<<

\msg_new:nnn { mytabular } { patch~failed } { Patching~of~\string#1~failed. }
\tl_new:N \g__mytabular_bol_hook_private_tl
\tl_new:N \g__mytabular_eol_hook_private_tl
\tl_new:N \l__mytabular_bol_hook_public_tl
\tl_new:N \l__mytabular_eol_hook_public_tl
\int_new:N \g__mytabular_current_row_int
\cs_new:Npn \mytabular@BoLHook% >>=
  {
    \g__mytabular_bol_hook_private_tl
    \l__mytabular_bol_hook_public_tl
  }% =<<
\cs_new:Npn \mytabular@BoLHook@private%>>=
  {
    \g__mytabular_bol_hook_private_tl
  }%=<<
\cs_new:Npn \mytabular@EoLHook% >>=
  {
    \g__mytabular_eol_hook_private_tl
    \l__mytabular_eol_hook_public_tl
  }% =<<
\cs_new_protected:Npn \mytabular@@arraystarthook% >>=
  {
    \int_gzero:N \g__mytabular_current_row_int
  }% =<<
\cs_new_protected:Npn \mytabular_step_row:% >>=
  {
    \int_gincr:N \g__mytabular_current_row_int
  }% =<<
\cs_new_protected:Npn \mytabular_addto_private_bol_hook:n #1% >>=
  {
    \tl_gput_right:Nn \g__mytabular_bol_hook_private_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_addto_private_eol_hook:n #1% >>=
  {
    \tl_gput_right:Nn \g__mytabular_eol_hook_private_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_clear_private_bol_hook:% >>=
  {
    \tl_gclear:N \g__mytabular_bol_hook_private_tl
  }% =<<
\cs_new_protected:Npn \mytabular_clear_private_eol_hook:% >>=
  {
    \tl_gclear:N \g__mytabular_eol_hook_private_tl
  }% =<<
\cs_new_protected:Npn \mytabular_addto_public_bol_hook:n #1% >>=
  {
    \tl_put_right:Nn \l__mytabular_bol_hook_public_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_addto_public_eol_hook:n #1% >>=
  {
    \tl_put_right:Nn \l__mytabular_eol_hook_public_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_clear_public_bol_hook:% >>=
  {
    \tl_clear:N \l__mytabular_bol_hook_public_tl
  }% =<<
\cs_new_protected:Npn \mytabular_clear_public_eol_hook:% >>=
  {
    \tl_clear:N \l__mytabular_eol_hook_public_tl
  }% =<<
\cs_new_protected:Npn \mytabular_patchcmd:Nnn #1 #2 #3% >>=
  {
    \patchcmd #1 { #2 } { #3 } {} 
      { \msg_error:nnn { mytabular } { patch~failed} { #1 } }
  }% =<<
\cs_new_protected:Npn \mytabular_pretocmd:Nn #1 #2% >>=
  {
    \pretocmd #1 { #2 } {} { \msg_error:nnn { mytabular } { patch~failed } { #1 } }
  }% =<<
\cs_new_protected:Npn \mytabular_apptocmd:Nn #1 #2% >>=
  {
    \apptocmd #1 { #2 } {} { \msg_error:nnn { mytabular } { patch~failed } { #1 } }
  }% =<<
\cs_new_protected:Npn \mytabular_backup_array:%>>=
  {
    \cs_set_eq:NN \@@array_unpatched      \@@array
    \cs_set_eq:NN \@arraycr_unpatched     \@arraycr
    \cs_set_eq:NN \@xarraycr_unpatched    \@xarraycr
    \cs_set_eq:NN \@xargarraycr_unpatched \@xargarraycr
    \cs_set_eq:NN \@yargarraycr_unpatched \@yargarraycr
    \cs_set_eq:NN \tabular_unpatched      \tabular
    \cs_set_eq:NN \endtabular_unpatched   \endtabular
    \cs_set_eq:NN \array_unpatched        \array
    \cs_set_eq:NN \endarray_unpatched     \endarray
  }%=<<
\cs_new_protected:Npn \mytabular@unpatcharray% >>=
  {
    \cs_set_eq:NN \@@array      \@@array_unpatched
    \cs_set_eq:NN \@arraycr     \@arraycr_unpatched
    \cs_set_eq:NN \@xarraycr    \@xarraycr_unpatched
    \cs_set_eq:NN \@xargarraycr \@xargarraycr_unpatched
    \cs_set_eq:NN \@yargarraycr \@yargarraycr_unpatched
    \cs_set_eq:NN \tabular      \tabular_unpatched
    \cs_set_eq:NN \endtabular   \endtabular_unpatched
    \cs_set_eq:NN \array        \array_unpatched
    \cs_set_eq:NN \endarray     \endarray_unpatched
  }% =<<
\mytabular_addto_private_bol_hook:n { \noalign { \mytabular_step_row: } }
\cs_new_protected:Npn \mytabular_patch:%>>=
  {
    \mytabular_backup_array:
    \mytabular_pretocmd:Nn  \tabular      { \mytabular@unpatcharray }
    \mytabular_pretocmd:Nn  \array        { \mytabular@unpatcharray }
    \mytabular_pretocmd:Nn  \@@array      { \mytabular@@arraystarthook }
    \mytabular_pretocmd:Nn  \@arraycr     { \mytabular@EoLHook }
    \mytabular_apptocmd:Nn  \@yargarraycr { \mytabular@BoLHook }
    \mytabular_patchcmd:Nnn \@xarraycr    { \cr } { \cr \mytabular@BoLHook }
    \mytabular_patchcmd:Nnn \@xargarraycr { \cr } { \cr \mytabular@BoLHook }
    \mytabular_patchcmd:Nnn \@@array      { \cr }
      { \cr \noexpand \mytabular@BoLHook@private }
  }%=<<
\NewDocumentEnvironment {mytabular} {}%>>=
  {
    \mytabular_patch:
    \tabular_unpatched
  }
  {
    \endtabular
  }%=<<
\makeatother
\ExplSyntaxOff


\begin{document}
\begin{mytabular}{!{\whimsicalrule{2-5}}l!{\whimsicalrule{1}}l!{\whimsicalrule{1,3,5}}}
  a & b \\
  a & b \\
  a & b \\
  a & b \\
  a & b \\
  a
\end{mytabular}
\end{document}
```

Result:

![weirdlines-1.png](/image?hash=faf8a459c5251274cc8221a9c756fdb67e12150dbca9e6e20ad9e755022ba85d)

## Adding `\wrule`

The following will add the two macros `\wrule` and `\Wrule`. `\Wrule` has to be used as the first thing in a row just like `\hline` or similar. It can be used to toggle the first `\whimsicalrule` in a row. `\wrule` on the other hand can be used to toggle the next `\whimsicalrule` and can be used anywhere, but you can't use it for the first rule in a row. Note that you still need to provide `!{\whimsicalrule}` in the argument of `mytabular` to have this work.

```
\documentclass[]{article}

\usepackage{xparse}
\usepackage{array}
\usepackage{etoolbox}

\ExplSyntaxOn
\makeatletter
\bool_new:N \g_whimsicalrule_once_bool
\NewDocumentCommand \wrule {}
  {
    \bool_gset_true:N \g_whimsicalrule_once_bool
  }
\NewExpandableDocumentCommand \Wrule {}
  {
    \tex_noalign:D { \bool_gset_true:N \g_whimsicalrule_once_bool }
  }
\NewDocumentCommand \whimsicalrule { m }%>>=
  {
    \exp_args:NV
    \tl_if_eq:nnTF \@currenvir { mytabular }
      { \whimsicalrule:n { #1 } }
      { \msg_error:nn { whimsicalrule } { not~in~mytabular } }
  }%=<<
\cs_new_protected:Npn \whimsicalrule_output:
  {
    \tex_vrule:D width \arrayrulewidth \relax
  }
\cs_new_protected:Npn \whimsicalrule:n #1 %>>=
  {
    \bool_if:NTF \g_whimsicalrule_once_bool
      {
        \bool_gset_false:N \g_whimsicalrule_once_bool
        \whimsicalrule_output:
      }
      {
        \clist_map_inline:nn { #1 }
          {
            \tl_if_in:nnTF { ##1 } { - }
              { \whimsicalrule_in_range:w ##1 \q_stop }
              { \whimsicalrule_if_eq:n { ##1 } }
          }
      }
  }%=<<
\cs_new_protected:Npn \whimsicalrule_in_range:w #1 - #2 \q_stop%>>=
  {
    \bool_lazy_and:nnT
      { \int_compare_p:nNn \g__mytabular_current_row_int > { #1 - \c_one_int } }
      { \int_compare_p:nNn \g__mytabular_current_row_int < { #2 + \c_one_int } }
      { \whimsicalrule_output: }
  }%=<<
\cs_new_protected:Npn \whimsicalrule_if_eq:n #1%>>=
  {
    \int_compare:nNnT \g__mytabular_current_row_int = { #1 }
      { \whimsicalrule_output: }
  }%=<<
\msg_new:nnn { whimsicalrule } { not~in~mytabular }%>>=
  { \string\whimsicalrule\space used~outside~of~`mytabular'~environment }%=<<

\msg_new:nnn { mytabular } { patch~failed } { Patching~of~\string#1~failed. }
\tl_new:N \g__mytabular_bol_hook_private_tl
\tl_new:N \g__mytabular_eol_hook_private_tl
\tl_new:N \l__mytabular_bol_hook_public_tl
\tl_new:N \l__mytabular_eol_hook_public_tl
\int_new:N \g__mytabular_current_row_int
\cs_new:Npn \mytabular@BoLHook% >>=
  {
    \g__mytabular_bol_hook_private_tl
    \l__mytabular_bol_hook_public_tl
  }% =<<
\cs_new:Npn \mytabular@BoLHook@private%>>=
  {
    \g__mytabular_bol_hook_private_tl
  }%=<<
\cs_new:Npn \mytabular@EoLHook% >>=
  {
    \g__mytabular_eol_hook_private_tl
    \l__mytabular_eol_hook_public_tl
  }% =<<
\cs_new_protected:Npn \mytabular@@arraystarthook% >>=
  {
    \int_gzero:N \g__mytabular_current_row_int
  }% =<<
\cs_new_protected:Npn \mytabular_step_row:% >>=
  {
    \int_gincr:N \g__mytabular_current_row_int
  }% =<<
\cs_new_protected:Npn \mytabular_addto_private_bol_hook:n #1% >>=
  {
    \tl_gput_right:Nn \g__mytabular_bol_hook_private_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_addto_private_eol_hook:n #1% >>=
  {
    \tl_gput_right:Nn \g__mytabular_eol_hook_private_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_clear_private_bol_hook:% >>=
  {
    \tl_gclear:N \g__mytabular_bol_hook_private_tl
  }% =<<
\cs_new_protected:Npn \mytabular_clear_private_eol_hook:% >>=
  {
    \tl_gclear:N \g__mytabular_eol_hook_private_tl
  }% =<<
\cs_new_protected:Npn \mytabular_addto_public_bol_hook:n #1% >>=
  {
    \tl_put_right:Nn \l__mytabular_bol_hook_public_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_addto_public_eol_hook:n #1% >>=
  {
    \tl_put_right:Nn \l__mytabular_eol_hook_public_tl { #1 }
  }% =<<
\cs_new_protected:Npn \mytabular_clear_public_bol_hook:% >>=
  {
    \tl_clear:N \l__mytabular_bol_hook_public_tl
  }% =<<
\cs_new_protected:Npn \mytabular_clear_public_eol_hook:% >>=
  {
    \tl_clear:N \l__mytabular_eol_hook_public_tl
  }% =<<
\cs_new_protected:Npn \mytabular_patchcmd:Nnn #1 #2 #3% >>=
  {
    \patchcmd #1 { #2 } { #3 } {} 
      { \msg_error:nnn { mytabular } { patch~failed} { #1 } }
  }% =<<
\cs_new_protected:Npn \mytabular_pretocmd:Nn #1 #2% >>=
  {
    \pretocmd #1 { #2 } {} { \msg_error:nnn { mytabular } { patch~failed } { #1 } }
  }% =<<
\cs_new_protected:Npn \mytabular_apptocmd:Nn #1 #2% >>=
  {
    \apptocmd #1 { #2 } {} { \msg_error:nnn { mytabular } { patch~failed } { #1 } }
  }% =<<
\cs_new_protected:Npn \mytabular_backup_array:%>>=
  {
    \cs_set_eq:NN \@@array_unpatched      \@@array
    \cs_set_eq:NN \@arraycr_unpatched     \@arraycr
    \cs_set_eq:NN \@xarraycr_unpatched    \@xarraycr
    \cs_set_eq:NN \@xargarraycr_unpatched \@xargarraycr
    \cs_set_eq:NN \@yargarraycr_unpatched \@yargarraycr
    \cs_set_eq:NN \tabular_unpatched      \tabular
    \cs_set_eq:NN \endtabular_unpatched   \endtabular
    \cs_set_eq:NN \array_unpatched        \array
    \cs_set_eq:NN \endarray_unpatched     \endarray
  }%=<<
\cs_new_protected:Npn \mytabular@unpatcharray% >>=
  {
    \cs_set_eq:NN \@@array      \@@array_unpatched
    \cs_set_eq:NN \@arraycr     \@arraycr_unpatched
    \cs_set_eq:NN \@xarraycr    \@xarraycr_unpatched
    \cs_set_eq:NN \@xargarraycr \@xargarraycr_unpatched
    \cs_set_eq:NN \@yargarraycr \@yargarraycr_unpatched
    \cs_set_eq:NN \tabular      \tabular_unpatched
    \cs_set_eq:NN \endtabular   \endtabular_unpatched
    \cs_set_eq:NN \array        \array_unpatched
    \cs_set_eq:NN \endarray     \endarray_unpatched
  }% =<<
\mytabular_addto_private_bol_hook:n { \noalign { \mytabular_step_row: } }
\cs_new_protected:Npn \mytabular_patch:%>>=
  {
    \mytabular_backup_array:
    \mytabular_pretocmd:Nn  \tabular      { \mytabular@unpatcharray }
    \mytabular_pretocmd:Nn  \array        { \mytabular@unpatcharray }
    \mytabular_pretocmd:Nn  \@@array      { \mytabular@@arraystarthook }
    \mytabular_pretocmd:Nn  \@arraycr     { \mytabular@EoLHook }
    \mytabular_apptocmd:Nn  \@yargarraycr { \mytabular@BoLHook }
    \mytabular_patchcmd:Nnn \@xarraycr    { \cr } { \cr \mytabular@BoLHook }
    \mytabular_patchcmd:Nnn \@xargarraycr { \cr } { \cr \mytabular@BoLHook }
    \mytabular_patchcmd:Nnn \@@array      { \cr }
      { \cr \noexpand \mytabular@BoLHook@private }
  }%=<<
\NewDocumentEnvironment {mytabular} {}%>>=
  {
    \mytabular_patch:
    \tabular_unpatched
  }
  {
    \endtabular
  }%=<<
\makeatother
\ExplSyntaxOff

\begin{document}
\begin{mytabular}{!{\whimsicalrule{2-5}}l!{\whimsicalrule{1}}l!{\whimsicalrule{1,3,5}}}
  a & b \\
  a & b \\
  a & b \\
  a\wrule & b \\
  a & b \\
  a & b \\
  \Wrule
  a
\end{mytabular}
\end{document}
```

## Primitive way to add lines

A primitive way to something similar to `\wrule` is to use `\multicolumn` to add a `|` to the current cell's alignment definition (but you'd need to enter the correct alignment type for each column -- if every column is the same type this is trivial)

```
\documentclass[]{article}

\usepackage{xparse}
\NewExpandableDocumentCommand \rrule { O{l} m }
  {
    \multicolumn{1}{#1|}{#2}
  }
\NewExpandableDocumentCommand \lrule { O{l} m }
  {
    \multicolumn{1}{|#1}{#2}
  }
\NewExpandableDocumentCommand \drule { O{l} m }
  {
    \multicolumn{1}{|#1|}{#2}
  }


\begin{document}
\begin{tabular}{ll}
  a & b \\
  \rrule{a} & b \\
  \drule{a} & b \\
  a & \rrule{b} \\
  \lrule{a} & \lrule{b} \\
\end{tabular}
\end{document}
```
Answer #2
joulev
Second answer as you want to grab everything inside a single matrix.

Why the lines are of different heights? Because node `b` is higher than node `a` and node `c`, as you can see here:

```
\documentclass[tikz,border=0.5cm]{standalone}
\usetikzlibrary{matrix,positioning,calc,decorations}
\usepackage{xparse}
\usepackage{environ}
\NewEnviron{antara}[1]{
\begin{tikzpicture}[transform shape]
\matrix (antara) [matrix of nodes,nodes={text width=2.5mm},ampersand replacement=\&]
{
\BODY
};
\foreach \x in {#1}
\draw (antara-1-\x.north west) -- (antara-2-\x.south west);
%\draw (antara.north west) -- (antara.south west);
%\draw (antara.north east) -- (antara.south east);
\draw node[below] at (antara-2-1.south) {$\times$};
\end{tikzpicture}
}

\begin{document}
    \begin{antara}{1,2,3}
        a \& b \& c\\
        d \& e \& f\\
    \end{antara}
\end{document}
```

![blob](/image?hash=30217db9939ade874482500fa2030a0b431c9cc858cd6e16c069aba184485661)

(as you can see, we also have node `e` is shorter than its neighbours.

How to solve this? Just make the nodes have equal heights. There are two ways:

* You can use `\vphantom` to make sure the nodes have the maximum height possible.

    ```
    \documentclass[tikz,border=0.5cm]{standalone}
    \usetikzlibrary{matrix,positioning,calc,decorations}
    \usepackage{xparse}
    \usepackage{environ}
    \NewEnviron{antara}[1]{
    \begin{tikzpicture}[transform shape]
    \matrix (antara) [matrix of nodes,nodes={text width=2.5mm,execute at begin node=\vphantom{hg}},ampersand replacement=\&]
    {
    \BODY
    };
    \foreach \x in {#1}
    \draw (antara-1-\x.north west) -- (antara-2-\x.south west);
    %\draw (antara.north west) -- (antara.south west);
    %\draw (antara.north east) -- (antara.south east);
    \draw node[below] at (antara-2-1.south) {$\times$};
    \end{tikzpicture}
    }
    
    \begin{document}
    \begin{antara}{1,2,3}
      a \& b \& c\\
      d \& e \& f\\
    \end{antara}
    \end{document}
    ```

    This gives a very good result, however it is language-dependent. You have to choose `hg` for different alphabet systems.
    
    EDIT: @samcarter proposes `\strut`, and it works wonderfully well. Thanks!
    
    ```
    \documentclass[tikz,border=0.5cm]{standalone}
    \usetikzlibrary{matrix,positioning,calc,decorations}
    \usepackage{xparse}
    \usepackage{environ}
    \NewEnviron{antara}[1]{
    \begin{tikzpicture}[transform shape]
    \matrix (antara) [matrix of nodes,nodes={text width=2.5mm,execute at begin node=\strut},ampersand replacement=\&]
    {
    \BODY
    };
    \foreach \x in {#1}
    \draw (antara-1-\x.north west) -- (antara-2-\x.south west);
    %\draw (antara.north west) -- (antara.south west);
    %\draw (antara.north east) -- (antara.south east);
    \draw node[below] at (antara-2-1.south) {$\times$};
    \end{tikzpicture}
    }
    
    \begin{document}
    \begin{antara}{1,2,3}
      a \& b \& c\\
      d \& e \& f\\
    \end{antara}
    \end{document}
    ```
    
* Or `minimum height` with `anchor=center`:

    ```
    % arara: pdflatex
    \documentclass[tikz,border=0.5cm]{standalone}
    \usetikzlibrary{matrix,positioning,calc,decorations}
    \usepackage{xparse}
    \usepackage{environ}
    \NewEnviron{antara}[1]{
    \begin{tikzpicture}[transform shape]
    \matrix (antara) [matrix of nodes,nodes={text width=2.5mm,minimum height=5mm,anchor=center},ampersand replacement=\&]
    {
    \BODY
    };
    \foreach \x in {#1}
    \draw (antara-1-\x.north west) -- (antara-2-\x.south west);
    %\draw (antara.north west) -- (antara.south west);
    %\draw (antara.north east) -- (antara.south east);
    \draw node[below] at (antara-2-1.south) {$\times$};
    \end{tikzpicture}
    }
    
    \begin{document}
    \begin{antara}{1,2,3}
      a \& b \& c\\
      d \& e \& f\\
    \end{antara}
    \end{document}
    ```
    
    This is not language-dependent, but the `b` and `e` looks a bit off, because the anchor is no longer `base`.
Answer #3
samcarter
Based on the example you've shown in https://topanswers.xyz/transcript?room=1008&id=43508#c43508 I suggest to use `nicematrix`. This has the advantage that you can arrange the first 4 letters of each block in an array with bars on each site and use the `last-row` option to place the bottom row outside of the vertical bars. 

```
\documentclass{article}

\usepackage{nicematrix}

\newcommand{\foo}[6][CC|]{%
$\begin{NiceArray}{#1}[last-row]
\text{#2} & \text{#3} \\
\text{#4} & \text{#5} \\
\text{#6} & \\
\end{NiceArray}$\space\space%
}

\begin{document}

\noindent\raggedright
\foo[|CC|]{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}

\foo[|CC|]{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}

\foo[|CC|]{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}

\foo[|CC|]{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}

\foo[|CC|]{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}\foo{a}{b}{c}{d}{e}

\end{document}
```

![Screen Shot 2020-05-05 at 14.55.23.png](/image?hash=681d19635f7aab8dfe7c88583d8f314e7fe5f7e0b5f6ae9ed56fe83ec9433a47)
Answer #4
user 3.14159
This may be thought as an extended list of comments, and parts of this post may be combined with parts of the other (excellent) answers. The upshot is that the `matrix` library has many hidden gems that are generally not appreciated, and some of which are not even documented. This touches them only very little.

1. You can have left- and right-aligned entries.
2. Related to that, you can have columns of equal width.
3. The matrix borders can be done with a path picture. 
4. There are keys like `execute at end matrix` and the counts like `\pgfmatrixcurrentrow` and `\pgfmatrixcurrentcolumn` which can help a lot in the construction of matrices, but at this point none of these is used here.

Here are some examples for the first three items.

```
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{matrix}
\usepackage{eqparbox}
\newbox\eqnodebox
\tikzset{equal size/.style={execute at begin
    node={\setbox\eqnodebox=\hbox\bgroup$},
    execute at end node={$\egroup\eqmakebox[#1][\pgfkeysvalueof{/tikz/equal size align}]{\copy\eqnodebox}}},
    equal size/.default=A,equal size align/.initial=c,
	LR border/.style={path picture={
 \draw ([xshift=\pgflinewidth/2]path picture bounding box.south west)
  -- ([xshift=\pgflinewidth/2]path picture bounding box.north west)
  ([xshift=-\pgflinewidth/2]path picture bounding box.south east)
  -- ([xshift=-\pgflinewidth/2]path picture bounding box.north east);
 }},antaramat/.style={matrix of nodes,LR border,inner ysep=0.5pt,
nodes={equal size=#1,text height=0.8em,text depth=0.25ex,inner ysep=2pt}},
antaramat/.default=A}
\begin{document}
\tikz{\node[antaramat]{
  a & b & c\\
  d & e & f\\
};}

\tikz{\node[equal size align=l,antaramat=B]{
  a_{12} & b_{21} & c_{12}\\
  d_1 & e_{1} & f_3\\
};}

\tikz{\node[equal size align=r,antaramat=C]{
  1 & -1 & -1\\
  -1 & 1 & -1\\
};}
\end{document}	
```

![Screen Shot 2020-05-05 at 8.37.51 PM.png](/image?hash=36457265d209bb20e26e3c7ab9896ac8480dd88a025056ff18b4a1e04619fd67)

While this is likely not what you finally want, it may provide some ideas for furhter upgrades.

Please note also that I like pgf keys a lot. Rather than defining a macro for everything I personally prefer defining styles. You can combine them. For instance, the `LR border` style may find its application in other tasks as well.
Answer #5
joulev
You can define each "cell" to be a Ti*k*Z matrix and save these matrixes to a parameterized Ti*k*Z `pic`. Everything left to be done is just positioning these pics, which can be done by using anchors.

Short example:

```
\documentclass[tikz,border=3pt]{standalone}
\usetikzlibrary{matrix}
\newif\ifdrawleftline
\drawleftlinefalse
\tikzset{
  draw left line/.code={\drawleftlinetrue},
  % #1: nw, #2: ne, #3: sw, #4: se, #5: the thing under sw, #6: name
  pics/antara/.style n args={6}{code={
    \begin{scope}[local bounding box=#6,ampersand replacement=\&,anchor=north west]
      \matrix (aux) [matrix of nodes,inner ysep=0pt,nodes={inner sep=.3333em}] {
        #1 \& #2 \\
        #3 \& #4 \\
      };
      \draw (aux.north east) -- (aux.south east)
            (aux-2-1.south) node[below] {#5};
      \ifdrawleftline
        \draw (aux.north west) -- (aux.south west);
      \fi
    \end{scope}
    \drawleftlinefalse
  }}
}
\begin{document}
\begin{tikzpicture}
  \pic[draw left line] at (0,0) {antara={a}{b}{c}{d}{e}{my antara}};
  \pic at (my antara.north east) {antara={a}{b}{c}{d}{e}{my antara 2}};
  \pic at (my antara 2.north east) {antara={a}{b}{c}{d}{e}{my antara 3}};
\end{tikzpicture}
\end{document}
```

![blob](/image?hash=5b267a519e5ea50355d976bde114685fc2ff6bc701bd9f4d4eb5d76707ee4e6e)

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.