문자의 평균 너비에 대한 매크로

문자의 평균 너비에 대한 매크로

LaTeX의 ConTeX 와 유사한 매크로를 어떻게 만들 수 있습니까 \averagecharwidth? 내 문서에 해당 문자의 빈도를 기반으로 문자의 평균 너비를 계산합니까? 해당 매크로는 다음에 표시됩니다.이것우편.

여기에 이미지 설명을 입력하세요

답변1

여기에 순진한 접근 방식이 있습니다.

  1. 전체 문서를 토큰 목록에 저장
  2. 각 알파벳 문자의 발생 횟수를 계산합니다(대부분).
  3. 각 문자 수를 총 알파벳 문자 수로 나누어 해당 문자의 상대 빈도를 구합니다.
  4. 해당 비율에 문자 너비를 곱하고 평균 문자 너비를 구하세요.

몇 가지 참고사항:

  • 중괄호 그룹은 단일 토큰으로 계산되므로 알파벳 문자와 \begin{environment}일치 \par하지 않으며 이는 장점입니다.
  • 동시에, 안에 있는 단어는 \text{some text}계산되지 않으므로 이것이 단점입니다.
  • 대문자도 고려할 수 있지만 속도가 느립니다.
  • 나는 중요한 것을 놓친 것 같지 않지만 당신은 결코 알지 못합니다.
  • 편집하다:이제 공백이 계산에 포함되며 매크로 효과는 누적됩니다. 나는 공간을 다룰 때 늘림과 수축이 결국 서로 상쇄되고, 공간의 평균 너비는 공간의 일반적인 너비와 같다는 가정을 세웠다. 누군가 이를 처리할 수 있는 더 좋은 방법이 있으면 알려주시기 바랍니다.
  • 편집하다:두 번 컴파일하여 텍스트 너비를 원하는 값으로 자동 조정합니다.

어쨌든 직선 텍스트의 경우 정확한 평균 문자 너비를 제공합니다. 중괄호 그룹에 더 많은 인쇄된 텍스트가 숨겨져 있으면 결과의 정확도가 떨어집니다.

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx}
\usepackage{booktabs}
\usepackage{environ}

\ExplSyntaxOn

\bool_new:N \g_has_run_bool
\tl_new:N \l_aw_text_tl
\int_new:N \l_aw_tot_int
\int_new:N \g_aw_tot_alph_int
\int_new:N \g_wid_space_int
\int_new:N \g_space_int
\fp_new:N \g_rat_space_int
\fp_new:N \g_aw_avg_width_fp
\dim_new:N \myalphabetwidth
\dim_new:N \mytextwidth
\input{testing.aux}
\tl_const:Nx \c_aw_the_alphabet_tl {abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.;?()!' \token_to_str:N :}

% this can be changed to an evironment or renamed or whatever
\NewDocumentCommand {\avgwidthstart} {}
  {
    \aw_avg_width:w
  }

\NewDocumentCommand {\avgwidthend}{}{}

% Here is the environment version, using just "text" as a name is probably a bad idea.
\NewEnviron{awtext}
{
  \expandafter\avgwidthstart\BODY\avgwidthend
}

\makeatletter

\cs_new:Npn \aw_avg_width:w #1 \avgwidthend
  {
    % if first run, then generate variables to be used
    \bool_if:NF \g_has_run_bool
      {
        \tl_map_inline:Nn \c_aw_the_alphabet_tl
        {
          \int_new:c {g_##1_int}
          \fp_new:c {g_rat_##1_fp}
          \fp_new:c {g_wid_##1_fp}
        }
      }
    \tl_set:Nn \l_aw_text_tl {#1}

    % this can be used rather than the preceding line to take capital 
    % letters into account, but is Slooooooow
    %\tl_set:Nx \l_aw_text_tl {\tl_expandable_lowercase:n {#1}}

    \int_set:Nn \l_aw_tot_int {\tl_count:N \l_aw_text_tl}
    \tl_map_function:NN \c_aw_the_alphabet_tl \aw_get_counts:n
    \deal_with_spaces:n {#1}
    \tl_map_function:NN \c_aw_the_alphabet_tl \aw_calc_ratios:n
    \tl_map_function:NN \c_aw_the_alphabet_tl \aw_calc_avg_width:n
    \fp_gset_eq:NN \g_aw_avg_width_fp \l_tmpa_fp
    \fp_zero:N \l_tmpa_fp

    % the dimension \myalphabetwidth gives the width of the alphabet based on your character freq,
    % can be accessed by \the\myalphabetwidth
    \dim_gset:Nn \myalphabetwidth {\fp_to_dim:n {\fp_eval:n {61*\g_aw_avg_width_fp}}}

    % the dimension \mytextwidth gives the recommended \textwidth based on 66 chars per line.
    % can be accessed by \the\mytextwidth
    \dim_gset:Nn \mytextwidth {\fp_to_dim:n {\fp_eval:n {66*\g_aw_avg_width_fp}}}
    \protected@write\@mainaux{}{\mytextwidth=\the\mytextwidth}
    \bool_gset_true:N \g_has_run_bool

    % and lastly print the content
    #1
  }

\makeatother

\cs_new:Npn \aw_get_counts:n #1
  {
    % make a temporary token list from the document body 
    \tl_set_eq:NN \l_tmpb_tl \l_aw_text_tl
    % remove all occurrences of the character
    \tl_remove_all:Nn \l_tmpb_tl {#1}
    % add to appropriate int the number of occurrences of that character in current block
    \int_set:Nn \l_tmpa_int {\int_eval:n{\l_aw_tot_int -\tl_count:N \l_tmpb_tl}}
    % add to appropriate int the number of occurrences of that character in current block
    \int_gadd:cn {g_#1_int} {\l_tmpa_int}
    % add this to the total
    \int_gadd:Nn \g_aw_tot_alph_int {\l_tmpa_int}
  }

\cs_new:Npn \deal_with_spaces:n #1
  {
    \tl_set:Nn \l_tmpa_tl {#1}
    % rescan body with spaces as characters
    \tl_set_rescan:Nnn \l_tmpb_tl {\char_set_catcode_letter:N \ }{#1}
    % find number of new characters introduced.  add to number of spaces and alph chars
    \int_set:Nn \l_tmpa_int {\tl_count:N \l_tmpb_tl -\tl_count:N \l_tmpa_tl}
    \int_gadd:Nn \g_space_int {\l_tmpa_int}
    \int_gadd:Nn \g_aw_tot_alph_int {\l_tmpa_int}
    % since this comes after the rest of chars are dealt with, tot_alph is final total
    \fp_set:Nn \g_rat_space_fp {\g_space_int/\g_aw_tot_alph_int}
    % get width of space and use it.  obviously space is stretchable, so i'll assume
    % that the expansions and contractions cancel one another over large text.  is this
    % a terrible assumption???
    \hbox_set:Nn \l_tmpa_box {\ }
    \fp_gset:Nn \g_wid_space_fp {\dim_to_fp:n {\box_wd:N \l_tmpa_box}}
    \fp_add:Nn \l_tmpa_fp {\g_wid_space_fp*\g_rat_space_fp}
  }

\cs_new:Npn \aw_calc_ratios:n #1
  {
    % divide number of occurrences of char by total alphabetic chars
    \fp_gset:cn {g_rat_#1_fp}{{\int_use:c {g_#1_int}}/\g_aw_tot_alph_int}
  }

\cs_new:Npn \aw_calc_avg_width:n #1
  {
    % only need to find char widths once
    \bool_if:NF \g_has_run_bool
      {
        % find width of char box
        \hbox_set:Nn \l_tmpa_box {#1}
        \fp_gset:cn {g_wid_#1_fp}{\dim_to_fp:n {\box_wd:N \l_tmpa_box}}
      }
    % multiply it by char frequency and add to avg width
    \fp_add:Nn \l_tmpa_fp {{\fp_use:c {g_wid_#1_fp}}*{\fp_use:c {g_rat_#1_fp}}}
  }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This part is just for fun. Delete it and the showtable command from the document if
% it isn't wanted
\tl_new:N \l_aw_tab_rows_tl
\seq_new:N \g_aw_the_alphabet_seq

\NewDocumentCommand {\showtable}{}
    {
      \clearpage
      \aw_make_table:
    }

\cs_generate_variant:Nn \seq_set_split:Nnn {NnV}
\cs_new:Npn \aw_make_table:
    {
      \thispagestyle{empty}
      \seq_set_split:NnV \g_aw_the_alphabet_seq {} \c_aw_the_alphabet_tl
      \seq_map_function:NN \g_aw_the_alphabet_seq \aw_generate_row:n
      \begin{table}
      \centering
      \sisetup{round-mode = places,round-precision = 5,output-decimal-marker={,},table-format = 3.5}
      \begin{tabular}{lll}
        \toprule
        {Average\,text\,width}&{Average\,character\,width}&{Average\,alphabet\,width}\\
        \midrule
        \the\mytextwidth&\fp_eval:n {round(\g_aw_avg_width_fp,5)}pt&\the\myalphabetwidth\\
        \bottomrule
      \end{tabular}\par
      \end{table}
      \vfil
      \centering
      \sisetup{round-mode = places,round-precision = 5,output-decimal-marker={,},table-format = 3.5}
      \begin{longtable}{cS}
        \toprule
        {Letter}&{Actual}\\
        \midrule
        spaces&\fp_eval:n {\g_rat_space_fp*100}\%\\
        \tl_use:N \l_aw_tab_rows_tl
        \bottomrule
      \end{longtable}\par
    }

\cs_new:Npn \aw_generate_row:n #1
    {
      \tl_put_right:Nn \l_aw_tab_rows_tl {#1&}
      \tl_put_right:Nx \l_aw_tab_rows_tl {\fp_eval:n {100*{\fp_use:c {g_rat_#1_fp}}}\%}
      \tl_put_right:Nn \l_aw_tab_rows_tl {\\}
    }

\ExplSyntaxOff

    \begin{document}

    \avgwidthstart
    My audit group's Group Manager and his wife have an infant I can describe only as fierce.
    Its expression is fierce; its demeanor is fierce; its gaze over bottle or pacifier or finger-fierce, 
    intimidating, aggressive. I have never heard it cry. When it feeds or sleeps, its pale face reddens,
    which makes it look all the fiercer.
    \avgwidthend

    \avgwidthstart
    On those workdays when our Group Manager, Mr. Yeagle, brought it in to the District office, hanging papoose-style in a nylon device on his back, the infant appeared to 
    be riding him as a mahout does an elephant. It hung there, radiating authority. Its back lay directly 
    against Mr. Yeagle's, its large head resting in the hollow of its father's neck and forcing our Group 
    Manager's head out and down into a posture of classic oppression. They made a creature with two faces,
    one of which was calm and blandly adult and the other unformed and yet emphatically fierce. The infant 
    never wiggled or fussed in the device. Its gaze around the corridor at the rest of us gathered waiting 
    for the morning elevator was level and unblinking and (it seemed) almost accusing. The infant's face, as 
    I experienced it, was mostly eyes and lower lip, its nose a mere pinch, its forehead milky and domed, 
    its pale red hair wispy, no eyebrows or lashes or even eyelids I could see. I never saw it blink. Its 
    features seemed suggestions only. It had roughly as much face as a whale does. I did not like it at all.\par\noindent
    http://harpers.org/media/pdf/dfw/HarpersMagazine-2008-02-0081893.pdf
    \avgwidthend

    \begin{awtext}
    Here is some more text in an environment this time.  This text is included in the calculation of the average width.
    \end{awtext}
    \showtable{}

    \end{document}

주어진 텍스트의 문자 빈도는 다음과 같습니다.

설명 이 "평균 문자 너비"에서 얻은 요점은 다음과 같습니다.

  • 사람들은 한 줄에 최대 66자를 사용하면 텍스트 가독성이 향상된다고 결정했습니다.
  • 줄 너비는 고정되어 있으므로 줄당 실제 문자 수는 입력한 문자에 따라 달라집니다 . 예를 들어 an 이 an 보다 넓기 때문에 all 의 줄 m은 all 의 줄보다 적은 수의 문자를 포함합니다 .imi
  • 따라서 한 줄에 대략 66자 정도의 적절한 줄 너비를 설정하려면 문서에 사용되는 문자의 상대적 빈도를 알아야 합니다. 대부분의 문자가 넓다면 더 넓은 선이 필요합니다. 대부분의 문자가 좁은 경우 그에 따라 더 좁은 선이 필요합니다.
  • 따라서 사용된 문자의 평균 너비를 계산하고 이를 사용하여 선 너비를 결정합니다. 예를 들어, 문서가 m's'와 i's'를 동일한 비율(50/50)로 구성한 경우 "평균 문자"의 너비는 an m과 an 의 너비 사이 어딘가에 있습니다 i. 특히 평균 문자에는 너비가 있으므로 로 x=(wd(m)+wd(i))/2설정해야 합니다 . 임의의 문서에 대한 추정을 통해 문서 내 상대 빈도에 따라 사용된 문자 너비의 가중 평균을 계산하고 여기에 66을 곱하여(또는 어떤 방식으로든 사용하여) 한 줄에 66자를 가장 잘 수용하는 값을 얻습니다. 기준.\textwidth66*x\textwidth

답변2

매크로는 상당히 낮은 수준의 TeX이므로 몇 가지 누락된 정의를 추가하면 LaTeX에서 쉽게 사용할 수 있습니다. 이러한 정의가 적용되면 간단히 가져올 수 있습니다.랭-frq.mkii,
랭-frd.mkii및 도우미 파일지원-mis.mkii(대상 페이지에서 클릭 raw하여 다운로드) ConTeXt를 \averagecharwidth직접 사용하세요.

% Copy definition of \emptybox from supp-box.mkii
\ifx\voidbox\undefined      \newbox\voidbox \fi
\def\emptybox{\box\voidbox}

% Copy definition of \startnointerference from syst-new.mkii
\newbox\nointerferencebox

\def\startnointerference
  {\setbox\nointerferencebox\vbox
   \bgroup}

\def\stopnointerference
  {\egroup
   \setbox\nointerferencebox\emptybox}

% Load a trimmed down version of ConTeXt macros
\input supp-mis.mkii

\input lang-frq.mkii 
\input lang-frd.mkii

% Set the main language. (I don't know what the LateX equivalent of
% \currentmainlanguage)
\def\currentmainlanguage{en}

\documentclass{article}
\begin{document}
The average character width is \the\averagecharwidth
\end{document}

메모: lang-frd.mkii(읽는 것 \startcharactertable[en] 100 x \stopcharactertable % kind of default)의 116번째 줄을 주석 처리합니다.

관련 정보