diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1428d53..91a82db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@ instead of version numbers.
## 2023-12-14
+* `\begin{tabular}` improvements:
+ * `*` repetitions supported: `*3c` is shorthand for `ccc`,
+ `*{10}{c}` is shorthand for `cccccccccc`,
+ `*3{lr}` is shorthand for `lrlrlr`.
* Copy/pasting a URL from a message no longer adds extraneous zero-width spaces
* `\verb|$|` now works both inside and outside math mode
diff --git a/lib/formats.coffee b/lib/formats.coffee
index 3c2f3ba..03a129f 100644
--- a/lib/formats.coffee
+++ b/lib/formats.coffee
@@ -299,9 +299,16 @@ latex2htmlCommandsAlpha = (tex, math) ->
(match, char, verb) => "#{latexEscape verb}
"
## Process tabular environments first in order to split cells at &
## (so e.g. \bf is local to the cell)
- .replace /\\begin\s*{tabular}\s*{([^{}]*)}([^]*?)\\end\s*{tabular}/g, (m, cols, body) ->
+ .replace /\\begin\s*{tabular}\s*{((?:[^{}]|{[^{}]*})*)}([^]*?)\\end\s*{tabular}/g, (m, cols, body) ->
cols = cols.replace /\|/g, '' # not yet supported
body = body.replace /\\hline\s*|\\cline\s*{[^{}]*}/g, '' # not yet supported
+ cols = cols.replace /\*(\d|{\d+})([^{}]|{(?:[^{}]|{[^{}]*})*})/g,
+ (match, repeat, body) =>
+ body = body[1...-1] if body[0] == '{'
+ repeat = parseInt (repeat.replace /[{}]/g, ''), 10
+ repeat = 0 if repeat < 0
+ repeat = 1000 if repeat > 1000
+ body.repeat repeat
skip = (0 for colnum in [0...cols.length])
'