So I want to import a text file into latex character by character and format the individual characters by changing their color. So for instance, 'a' would be the color blue, 'b' would be red etc.

How should I go about importing the file? Should I make a database?

The input file is a simple text file extracted from fiction ebooks. I don't care much about the original formatting since the text file will be extracted from pdf or epub. So no equations and no special characters other than the one used in everyday english(. , ! ?).

So the input would probably be like:

"As an instance of what I mean, I remember meeting Monty Byng in Bond Street one morning, looking the last word in a grey check suit, and I felt I should never be happy till I had one like it."

  • 2
    Welcome to TeX.SX! Can you improve your question with some examples? – egreg Feb 10 '15 at 10:15
  • I'm actually new to latex. I'm learning latex in order to solve this problem of mine. That of reformatting normal text files so that letters are of different colors. So I assumed latex would be the way to go about this. The documentation of 'datatool' has left me a little overwhelmed and I needed a jumping off point with respect to what exactly I should use to import the text file into latex. – codemonkeyyy Feb 10 '15 at 10:19
  • @codemonkeyyy datatool is for maniuplating databases: if we are talking free-form text there are alternative approaches. What deterimines the colour applicable to each letter? – Joseph Wright Feb 10 '15 at 10:34
  • @JosephWright The colors are predetermined. So all 'a's would be one color, 'b's another color. So I'll have a number of conditions for each character I import. Or on parsing each row I import. What do you think the best approach would be? – codemonkeyyy Feb 10 '15 at 10:41
  • 1
    Have a look at the chickenize package and use LuaTeX. – Martin Schröder Feb 10 '15 at 13:02
up vote 7 down vote accepted

For each letter used, let's say "x", there can be a corresponding macro \xxx with its color defined. This can be done with punctuation marks, for example exclamation points, via \expandafter\def\csname!!!\endcsname{...}.

The text is passed by way of macro \colorize.

EDITED for getting data from a file.

EDITED for using triple letters \lll as colorizing name, lest things like \ll confuse the algorithm.

EDITED so that non defined colorizing macros are presented in black.

Added an ADDENDUM (see bottom of this answer) to allow for an escape character to give primitive formatting ability within the \colorize macro argument.

The file sample.tex contains this data

cba def abc!

Here is my next pair of graphs!!!

Here is the file that reads and parses it.

\documentclass{article}
\usepackage{readarray}
\usepackage{xcolor}
\newcommand\colorize[1]{\expandafter\colorizepars#1\par\relax\relax}
\long\def\colorizepars#1\par#2\relax{%
  \ifx#1\relax\else
    \colorizewords#1 \relax\relax%
  \fi%
  \ifx\relax#2\else\par\colorizepars#2\relax\fi%
}
\def\colorizewords#1 #2\relax{%
  \ifx#1\relax\else
    \colorizeletters#1\relax\relax%
  \fi%
  \ifx\relax#2\else\ \colorizewords#2\relax\fi%
}
\makeatletter
\def\colorizeletters#1#2\relax{%
  \@ifundefined{#1#1#1}{#1}{\csname#1#1#1\endcsname}%
  \ifx\relax#2\else\colorizeletters#2\relax\fi}
\makeatother

\def\aaa{\textcolor{red}{a}}
\def\bbb{\textcolor{blue}{b}}
\def\ccc{\textcolor{green}{c}}
\def\ddd{\textcolor{cyan}{d}}
\def\eee{\textcolor{red!40}{e}}
\def\fff{\textcolor{blue!40}{f}}
\def\ggg{\textcolor{red!30!blue}{g}}
\def\hhh{\textcolor{green!40}{h}}
\def\nnn{\textcolor{yellow!40!green}{n}}
\def\ppp{\textcolor{orange}{p}}
\def\rrr{\textcolor{blue!30}{r}}
\def\ttt{\textcolor{green!40!blue}{t}}
\def\xxx{\textcolor{black!50}{x}}
\expandafter\def\csname!!!\endcsname{\textcolor{yellow}{!}}

\def\colorizeentry#1{\edef\tmp{\arrayij{mydata}{#1}{1}}\colorize{\tmp}}

\begin{document}
\colorize{%
abc def!

next paragraph Undefined letters are black.
}

Here is a way to get it from a file, if paragraphs are not needed

\readdef{sample.tex}{\x}
\colorize{\x}

If paragraphs are needed, you can place each paragraph in its own single row 
of the input file and parse line by line.

\copyrecords{mydata}% USES DATA FROM MOST RECENT \readdef; ASSIGNS ROWS TO "mydata"
\colorizeentry{1}

\colorizeentry{2}

\colorizeentry{3}
\end{document}

ZOOM IN

enter image description here

ZOOM OUT

enter image description here


ADDENDUM:

If you needed some primitive formatting ability in the colorized text, you could build in an escape character (here the [) as such:

\makeatletter
\def\colorizeletters#1#2#3\relax{%
  \ifx [#1\EscapeChar{#2}%
    \ifx\relax#3\else\colorizeletters#3\relax\fi%
  \else%
    \@ifundefined{#1#1#1}{#1}{\csname#1#1#1\endcsname}%
    \ifx\relax#2\else\colorizeletters#2#3\relax\relax\fi%
  \fi%
}
\makeatother
\def\EscapeChar#1{%
  \if 0#1\relax \textcolor{blue}{[}\else%
  \if 1#1\relax \bfseries\else%
  \if 2#1\relax \mdseries\else%
  \if 3#1\relax \itshape\else%
  \if 4#1\relax \upshape\else%
  \fi\fi\fi\fi\fi%
}

Then, the following code

\colorize{%
abc def!

next [1paragraph[2 [0Undefined] [3letters[4 are black.
}

would display as

enter image description here

  • Looks awesome. This means I don't need to go the database route at all. It'll take me a little time to understand it fully though. – codemonkeyyy Feb 10 '15 at 12:00
  • @codemonkeyyy Please see my revision. I fixed a bug that broke the code on repeated letters. I also added a means to extract data from a file. – Steven B. Segletes Feb 10 '15 at 12:18
  • @codemonkeyyy I have revised it so that non-defined sequences are presented in black. I now also use three letters \aaa, for example, since there exist repeated two letter sequences like \ll. – Steven B. Segletes Feb 10 '15 at 12:36
  • @codemonkeyyy I have provided an addendum to allow for an "escape character [ that can be used to provide for primitive forms of text formatting. – Steven B. Segletes Feb 10 '15 at 14:24
  • there are actually two three-letter commands defined in a fairly commonly-used package, amssymb: \lll (much less than) and \ggg (much greater than). but if the text in question contains no math, that package probably won't be loaded. – barbara beeton Feb 10 '15 at 15:55

With lualatex you could do something along the line of the chickenize package:

\documentclass{article}
\usepackage{fontspec,luacode}
\usepackage{luatexbase}
\begin{luacode}
 -- stolen from chickenize
 local nodenew = node.new
 local nodecopy = node.copy
 local nodetail = node.tail
 local nodeinsertbefore = node.insert_before
 local nodeinsertafter = node.insert_after
 local noderemove = node.remove
 local nodeid = node.id
 local nodetraverseid = node.traverse_id
 local nodeslide = node.slide

 Hhead = nodeid("hhead")
 RULE = nodeid("rule")
 GLUE = nodeid("glue")
 WHAT = nodeid("whatsit")
 COL = node.subtype("pdf_colorstack")
 GLYPH = nodeid("glyph")
 color_push = nodenew(WHAT,COL)
 color_pop = nodenew(WHAT,COL)
 color_push.stack = 0
 color_pop.stack = 0
 color_push.command = 1
 color_pop.command = 2


 mycolors={}
 mycolors[97]="1 0 0" --a
 mycolors[98]="0 1 0" --b
 mycolors[99]="0 0 1" --c
 mycolors[100]="0 1 1" --d

colortext = function(head)
  for line in nodetraverseid(0,head) do
    for i in nodetraverseid(37,line.head) do
        if mycolors[i.char] then     
        color_push.data = mycolors[i.char].." rg"  
        else 
        color_push.data = "0.5 0.5 0.5 rg"  -- gray for undefined
        end
        line.head = nodeinsertbefore(line.head,i,nodecopy(color_push))
        nodeinsertafter(line.head,i,nodecopy(color_pop))     
    end
  end
  return head
end

\end{luacode}

\def\colortext{
  \directlua{luatexbase.add_to_callback("post_linebreak_filter",colortext,"colortext")}}
\def\uncolortext{
  \directlua{luatexbase.remove_from_callback("post_linebreak_filter","colortext")}}

\newcommand\mytext{abcde}  
\begin{document}
\colortext abcdefgabc \section{abcxse}  \mytext

\uncolortext abcdefgabc
\end{document} 

Which gives something like this. (I don't know why the number of the section is black). enter image description here

An expl3 version. The input (that can be from a file) is split into words and each word is split into letters that are colorized according to a table that can be easily augmented.

Limitations: only ASCII characters are allowed (unless you use XeLaTeX or LuaLaTeX and augment the table according to your wishes).

\begin{filecontents*}{filetocolorize.tex}
This file will be input.

Its words will be colorized.
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}

\ExplSyntaxOn
\NewDocumentCommand{\colorize}{+m}
 {
  \codemonkey_colorize:n { #1 }
 }

\NewDocumentCommand{\colorizeinput}{m}
 {
  \tl_set_from_file:Nnn \l_codemonkey_colorize_input_tl { } { #1 }
  \codemonkey_colorize:V \l_codemonkey_colorize_input_tl
 }

\tl_new:N \l_codemonkey_colorize_input_tl
\seq_new:N \l_codemonkey_colorize_words_seq

\cs_new_protected:Npn \codemonkey_colorize:n #1
 {
  \seq_set_split:Nnn \l_codemonkey_colorize_words_seq { ~ } { #1 }
  \seq_map_inline:Nn \l_codemonkey_colorize_words_seq
   {
    \tl_map_inline:nn { ##1 } { \codemonkey_colorize_letter:n { ####1 } }
    \c_space_tl
   }
  \unskip % remove the last added space
 }

\cs_generate_variant:Nn \codemonkey_colorize:n { V }

\cs_new_protected:Npn \codemonkey_colorize_letter:n #1
 {
  \str_case:nnF { #1 }
   {
    {a}{\textcolor{red}{a}}
    {b}{\textcolor{blue}{b}}
    {c}{\textcolor{green}{c}}
    {d}{\textcolor{cyan}{d}}
    {e}{\textcolor{red!40}{e}}
    {f}{\textcolor{blue!40}{f}}
    {g}{\textcolor{red!30!blue}{g}}
    {h}{\textcolor{green!40}{h}}
    {n}{\textcolor{yellow!40!green}{n}}
    {p}{\textcolor{orange}{p}}
    {r}{\textcolor{blue!30}{r}}
    {t}{\textcolor{green!40!blue}{t}}
    {x}{\textcolor{black!50}{x}}
    {!}{\textcolor{yellow}{!}}
   }
   { % none of the above
    #1
   }
 }
\ExplSyntaxOff

\begin{document}

\colorize{abc def! 

next paragraph Undefined letters are black.}

Here is a way to get it from a file

\colorizeinput{filetocolorize}

\end{document}

enter image description here

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.