Respectable-abbreviations macro











up vote
7
down vote

favorite
1












How might one write a macro that makes slovenly abbreviations respectable?



documentclass{article}
% newcommandabr{...}
begin{document}
I've seen it in the abr{OED}.
end{document}


What I mean is that OED should be rendered as O.,E.,D..



As Mico points out, there should never be two contiguous points. I
suppose one might use @ifnextchar. to prevent that.










share|improve this question
























  • Are you sure that you want two . punctuation marks after the (non-slovenly) version of OED?
    – Mico
    Nov 8 at 16:41








  • 1




    @Mico, I'm sure I don't; edited.
    – Toothrot
    Nov 8 at 19:42






  • 1




    Note however that the norm is that abbreviations should be typeset without any dots. I don't have the reference to the norm right now, but I'll post it later on.
    – Massimo Ortolano
    Nov 9 at 7:44















up vote
7
down vote

favorite
1












How might one write a macro that makes slovenly abbreviations respectable?



documentclass{article}
% newcommandabr{...}
begin{document}
I've seen it in the abr{OED}.
end{document}


What I mean is that OED should be rendered as O.,E.,D..



As Mico points out, there should never be two contiguous points. I
suppose one might use @ifnextchar. to prevent that.










share|improve this question
























  • Are you sure that you want two . punctuation marks after the (non-slovenly) version of OED?
    – Mico
    Nov 8 at 16:41








  • 1




    @Mico, I'm sure I don't; edited.
    – Toothrot
    Nov 8 at 19:42






  • 1




    Note however that the norm is that abbreviations should be typeset without any dots. I don't have the reference to the norm right now, but I'll post it later on.
    – Massimo Ortolano
    Nov 9 at 7:44













up vote
7
down vote

favorite
1









up vote
7
down vote

favorite
1






1





How might one write a macro that makes slovenly abbreviations respectable?



documentclass{article}
% newcommandabr{...}
begin{document}
I've seen it in the abr{OED}.
end{document}


What I mean is that OED should be rendered as O.,E.,D..



As Mico points out, there should never be two contiguous points. I
suppose one might use @ifnextchar. to prevent that.










share|improve this question















How might one write a macro that makes slovenly abbreviations respectable?



documentclass{article}
% newcommandabr{...}
begin{document}
I've seen it in the abr{OED}.
end{document}


What I mean is that OED should be rendered as O.,E.,D..



As Mico points out, there should never be two contiguous points. I
suppose one might use @ifnextchar. to prevent that.







macros






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 at 19:48

























asked Nov 8 at 12:36









Toothrot

1,359417




1,359417












  • Are you sure that you want two . punctuation marks after the (non-slovenly) version of OED?
    – Mico
    Nov 8 at 16:41








  • 1




    @Mico, I'm sure I don't; edited.
    – Toothrot
    Nov 8 at 19:42






  • 1




    Note however that the norm is that abbreviations should be typeset without any dots. I don't have the reference to the norm right now, but I'll post it later on.
    – Massimo Ortolano
    Nov 9 at 7:44


















  • Are you sure that you want two . punctuation marks after the (non-slovenly) version of OED?
    – Mico
    Nov 8 at 16:41








  • 1




    @Mico, I'm sure I don't; edited.
    – Toothrot
    Nov 8 at 19:42






  • 1




    Note however that the norm is that abbreviations should be typeset without any dots. I don't have the reference to the norm right now, but I'll post it later on.
    – Massimo Ortolano
    Nov 9 at 7:44
















Are you sure that you want two . punctuation marks after the (non-slovenly) version of OED?
– Mico
Nov 8 at 16:41






Are you sure that you want two . punctuation marks after the (non-slovenly) version of OED?
– Mico
Nov 8 at 16:41






1




1




@Mico, I'm sure I don't; edited.
– Toothrot
Nov 8 at 19:42




@Mico, I'm sure I don't; edited.
– Toothrot
Nov 8 at 19:42




1




1




Note however that the norm is that abbreviations should be typeset without any dots. I don't have the reference to the norm right now, but I'll post it later on.
– Massimo Ortolano
Nov 9 at 7:44




Note however that the norm is that abbreviations should be typeset without any dots. I don't have the reference to the norm right now, but I'll post it later on.
– Massimo Ortolano
Nov 9 at 7:44










6 Answers
6






active

oldest

votes

















up vote
7
down vote













All in all the same as the answer by Steven B. Segletes, but expandable. Also almost everything as contents should be fine (except the really unlikely endabr@).



documentclass{article}

makeatletter
newcommandabr[1]
{%
abr@#1endabr@
}
defabr@#1#2endabr@
{%
#1.%
ifrelaxdetokenize{#2}relax
@%
expandafter@gobble
else
,%
expandafter@firstofone
fi
{abr@#2endabr@}%
}
makeatother

begin{document}
Single letter:
abr{eg}

Multi letter:
abr{{th}e}
end{document}





share|improve this answer

















  • 1




    I believe mine is fully expandable, as well.
    – Steven B. Segletes
    Nov 8 at 12:59










  • @StevenB.Segletes def is not expandable.
    – Skillmon
    Nov 8 at 13:00










  • Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
    – Steven B. Segletes
    Nov 8 at 13:01










  • @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
    – Skillmon
    Nov 8 at 13:02






  • 1




    @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
    – Skillmon
    Nov 8 at 13:05


















up vote
6
down vote













Here is the simplest form of my original approach. It can be placed in an edef. Its only drawback is that it can blow the stack if the argument is too long (maybe 256 characters??)



documentclass{article}
newcommandabr[1]{abraux#1relaxrelax}
defabraux#1#2relax{#1.ifxrelax#2relax@else,abraux#2relaxfi}
begin{document}
Here is abr{OED} abbreviation.

Here is abr{XO} abbreviation.
end{document}


enter image description here



If that really were an issue, here is an alternative that doesn't have that problem.



There seems to be a misunderstanding that this definition of abr cannot be placed into an edef. It can. Naturally, the expansion is not necessarily pretty, but it will yield the proper typesetting. The only proviso is that @MyOwnMacro is not used elsewhere in your document.



documentclass{article}
usepackage[T1]{fontenc}
makeatletter
let@MyOwnMacrorelax
newcommandabr[1]{abraux#1relaxrelax}
defabraux#1#2relax{%
#1.ifxrelax#2relaxdef@MyOwnMacro{@}elsedef@MyOwnMacro{,abraux#2relax}fi%
@MyOwnMacro%
}
makeatother
begin{document}
Here is abr{OED} abbreviation.

Here is abr{XO} abbreviation.

Can be edef'ed:

edeftmp{abr{OED}} detokenizeexpandafter{tmp}

expands to tmp
end{document}


enter image description here






share|improve this answer



















  • 1




    Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
    – Sebastiano
    Nov 8 at 12:51








  • 1




    @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
    – Steven B. Segletes
    Nov 8 at 12:58










  • It can't be edefed if it is used for the first time! It'll throw an error.
    – Skillmon
    Nov 8 at 13:55










  • @Skillmon OK, letnextrelax fixes that.
    – Steven B. Segletes
    Nov 8 at 14:16






  • 2




    @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
    – Skillmon
    Nov 8 at 14:21


















up vote
6
down vote













Here's a LuaLaTeX-based solution.




  • Cases such as abr{OED} or abr{IMF} work just as expected. If the acronym contains both uppercase and lowercase letters, dots are inserted only before the uppercase letters in the interior of the acronym. E.g., abr{MSc} generates M.,Sc., and abr{PhD} generates Ph.,D..


  • It can handle mixed-case acronyms such as "PhD" directly -- no need to write abr{{Ph}D}.


  • If a "slovenly abbreviation" ends a sentence, one should place the "." punctuation mark inside the argument of abr. The code takes care to insert a @ "space factor* directive before the final . character. This, in turn, informs LaTeX that that . character should be treated as ending a sentence.


  • The code returns nothing if the argument of abr is either empty or expands to return nothing. E.g., defttt{} /abr{ttt}/ returns //. If the code encounters non-letter characters -- say, ( and ) -- no periods are inserted before or after them.


  • The code is expandable in the sense that abr can be included in the argument of an edef directive.



enter image description here



documentclass{article}
usepackage{luacode} % for 'luacode' environment

%% Lua-side code:
begin{luacode}


function abr ( s )
n = string.len ( s )
-- Do nothing unless "s" is non-empty.
if n>0 then
s_mod = "" -- initialize the string

-- Process the first n-1 characters in "s"
for i=1, n-1 do
s12 = string.sub ( s , i, i+1 )
s1 = string.sub ( s12, 1, 1 )
if string.match ( s12 , "%a%u" ) then
s_mod = s_mod .. s1 .. ".\,"
else
s_mod = s_mod .. s1
end
end

-- Process the final character in "s"
s_n = string.sub ( s , n)
if string.match (s_n, "%.") then -- "." char.
s_mod = s_mod .. "\@."
elseif string.match (s_n, "%l") then -- lowercase letter
s_mod = s_mod .. s_n .. ".\hbox{}"
elseif string.match (s_n, "%u") then -- uppercase letter
s_mod = s_mod .. s_n .. "."
else -- Any other character:
s_mod = s_mod .. s_n -- don't add anything after 's_n'
end


    -- Print the modified string
tex.sprint ( s_mod )
end
end

end{luacode}

%% LaTeX-side code: macro that calls the Lua function
newcommandabr[2]{directlua{abr("#1")}}

begin{document}
abr{OED}, abr{PhD}, abr{DPhil}, abr{MSc}, abr{()}

smallskip
% Two calls to "abr" with an empty argument (upon expansion):
.abr{}. quad
defttt{} .abr{ttt}.

bigskip
edeftmp{abr{MA}} detokenizeexpandafter{tmp}

edeftmp{abr{MA.}} detokenizeexpandafter{tmp}

expands to: tmp

smallskip
edeftmp{abr{MSc}} detokenizeexpandafter{tmp}

edeftmp{abr{MSc.}} detokenizeexpandafter{tmp}

expands to: tmp

bigskip
Some tests of spacing after punctuation marks:

smallskip
a abr{PhD} candidate --- good

a Ph.,D. candidate --- just to verify

smallskip
an abr{MSc} candidate --- good

an M.,Sc. candidate --- just to verify

smallskip
She has a abr{PhD.} So do I. --- good

She has a Ph.,D@. So do I. --- just to verify

smallskip
He has an abr{MSc.} So do I. --- good

He has an M.,Sc. So do I. --- just to verify

smallskip
Does he have an abr{MSc.}? Really?! --- good

Does he have an M.,Sc.? Really?! --- just to verify
end{document}





share|improve this answer























  • I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
    – Toothrot
    Nov 8 at 22:16










  • @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
    – Mico
    Nov 8 at 22:49










  • How about @ifnextchar.{spacefactor3000@gobble} or something like that?
    – Toothrot
    Nov 8 at 22:55










  • @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
    – Mico
    Nov 9 at 6:11


















up vote
5
down vote













Let TeX do the recursion:



documentclass{article}
usepackage{xparse}
usepackage{etoolbox}

robustify{,} % just in order it doesn't expand in edef

ExplSyntaxOn
NewExpandableDocumentCommand{abr}{m}
{
tl_map_function:fN { tl_range:nnn { #1 } { 1 } { -2 } } __toothrot_abr:n
tl_range:nnn { #1 } { -1 } { -1 } .
}
cs_generate_variant:Nn tl_map_function:nN { f }
cs_new:Nn __toothrot_abr:n { #1., }
ExplSyntaxOff

begin{document}

abr{OED}

abr{{Ph}D}

edeftest{abr{OED}}
texttt{meaningtest}

edeftest{abr{}}
texttt{meaningtest}

end{document}


If a part of the argument is braced, it is considered as a single item.



One might check whether the argument is empty in order to print nothing at all, but it doesn't seem so important a feature.



enter image description here



With tl_range:nnn { #1 } { 1 } { -2 } we extract all items but the last; tl_range:nnn { #1 } { -1 } { -1 } extracts the last item.






share|improve this answer




























    up vote
    5
    down vote













    documentclass{article}
    usepackage{xinttools}
    newcommandabr[1]{xintListWithSep{.,}{#1}.}
    begin{document}
    I've seen it in the abr{OED}.

    I got my abr{{Ph}D}.
    end{document}


    enter image description here



    Updated (à la Mico, but without LuaLaTeX)



    The syntax here is to use abr{PhD.} for example at end of a sentence, and abr{PhD} if not at end of a sentence.



    documentclass{article}
    usepackage{xinttools}
    makeatletter
    newcommandabr[1]
    {expandafter@gobbletworomannumeral0xintapplyunbracedabr@aux{#1}.@}
    defabr@sep{.,}
    defabr@aux#1{if.#1expandafterabr@end
    else
    if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
    expandafterexpandafterexpandafterabr@sep
    fi
    fi#1}%
    defabr@end.{ abr@@end}
    defabr@@end.@{@.}
    makeatother

    begin{document}%ttfamily
    I've seen it in the abr{OED}, and if located at end of a sentence
    just insert a dot in the verb|abr| argument: abr{OED.} It ended a
    sentence and in non-French spacing mode, TeX inserted the extra
    space.

    texttt{We can see it better with monospace font: abr{OED.} See?}

    I got my abr{PhD} and even my abr{PhilD}, leniency ruled
    in those days.

    texttt{The dots are added in a smart way: abr{AaaaBbbbCccc.} But it is
    assumed that the first letter is abr{Uppercased.} That's it.}

    texttt{Notice that neitger abr{Aaaa} nor abr{AaA} trigger an end of
    sentence spacing after the dot, which is abr{Good.} Isn't it?}
    end{document}


    enter image description here



    Again updated, for automatic end of sentence dot detection after abbreviation



    Here an end of sentence dot will be detected automatically.



    Of course we can't use @ifnextchar for that, as it swallows spaces.



    I added some comments about expandability, which seems to have drawn great attention in other answers :).



    documentclass{article}
    usepackage{shortvrb}MakeShortVerb{|}
    usepackage{xinttools}

    makeatletter
    protecteddefabrsep{.,}% maybe redefined even after edeffoo{abr{DPhil}}...
    protecteddefabrend{futurelet@let@tokenabr@end}
    defabr@end{ifx.@let@token@else.@fi}
    newcommandabr[1]
    {expandafter@gobbleromannumeral0xintapplyunbracedabr@aux{#1}abrend}
    defabr@aux#1{if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
    expandafterabr@sep
    fi#1}%
    defabr@sep{ abrsep}
    makeatother

    begin{document}%ttfamily
    I've seen it in the abr{OED}, and if located at end of a sentence
    it will detect it automatically: abr{OED}. There was no double dot.
    Besides, TeX applied its end of sentence extra space.

    texttt{We can see it better with monospace font: abr{OED}. See?}

    texttt{We can see it better with monospace font: abr{OED}, See?}

    I got a abr{MSc}, a abr{PhD} and even a abr{DPhil}. Leniency ruled
    in those days.

    {The abbreviation dots are added in a smart way, after the last
    lowercase letter following an uppercase letter:
    abr{AaaaBbbbCccc}. But it is emph{assumed} that the first letter is
    abr{Uppercased}. That's it.}

    texttt{Notice that neither abr{DPhil} nor abr{PhilD} get TeX to
    consider the inserted final dot as signaling an end of
    sentence spacing after the dot, which is abr{Good}. Isn't it?}

    About expandability, the correct way for LaTeX2e's users would be to use
    |protected@edef|, not a naked |edef|; although nowadays some
    LaTeX2e users have heard about |edef|, they might not know
    about |protected@edef|, which requires a cumbersome extra
    |makeatletter| for its usage. Anyway, none of that is described in
    textsc{Lamport} book, so I wonder if LaTeX2e users are really
    emph{allowed} into using |edef| to start with.

    But as it seems they know about |edef|, we as macro programmers need
    better to use the e-TeX's |protected| prefix and not the LaTeX2e
    |DeclareRobustCommand|, because users will not do |protected@edef|.

    This is what I have done here for a macro |abrsep| (why haven't we all
    used |abbr| by the way?) which is deliberately |protected|,
    allowing it to be redefined at location of use, long after some macro
    will have been defined via |edeffoo{abr{ABCDEFGH}}|.

    edeffoo{abr{ABCDEFGH}}texttt{stringfoo is meaningfoo}

    edeffoo{abr{AaaBccCcc}}texttt{stringfoo is meaningfoo}

    The |abrend| is also |protected|, anyway as its expansion will be
    context dependent (it detects if a dot follows), it had to not expand
    in the |edef|.
    end{document}


    enter image description here



    Notice that my proposals v2 and v3 will work only with ascii uppercase letters, no diacritics.






    share|improve this answer























    • @Mico I plagiarized your input syntax for end of sentence...
      – jfbu
      Nov 8 at 17:07






    • 1




      @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
      – jfbu
      Nov 9 at 8:21










    • Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
      – Mico
      Nov 9 at 8:39










    • (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
      – jfbu
      Nov 9 at 9:47




















    up vote
    4
    down vote













    documentclass{article}
    newcommandabr[1]{abraux#1..}
    defabraux#1#2#3{%
    #1%
    ifnum`#2>91relax% we have a lowercase letter following
    defnext{abraux#2#3}%
    else
    .ifx.#2defnext{@}else,defnext{abraux#2#3}fi
    fi
    next
    }
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.

    Here is abr{XOOED} abbreviation.

    abr{MSc}

    abr{DPhil}
    end{document}


    enter image description here






    share|improve this answer























    • Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
      – Mico
      Nov 9 at 6:20






    • 1




      Sure, if it is not an uppercase letter then go the next char.
      – Herbert
      Nov 9 at 19:02











    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "85"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f458975%2frespectable-abbreviations-macro%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    6 Answers
    6






    active

    oldest

    votes








    6 Answers
    6






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    7
    down vote













    All in all the same as the answer by Steven B. Segletes, but expandable. Also almost everything as contents should be fine (except the really unlikely endabr@).



    documentclass{article}

    makeatletter
    newcommandabr[1]
    {%
    abr@#1endabr@
    }
    defabr@#1#2endabr@
    {%
    #1.%
    ifrelaxdetokenize{#2}relax
    @%
    expandafter@gobble
    else
    ,%
    expandafter@firstofone
    fi
    {abr@#2endabr@}%
    }
    makeatother

    begin{document}
    Single letter:
    abr{eg}

    Multi letter:
    abr{{th}e}
    end{document}





    share|improve this answer

















    • 1




      I believe mine is fully expandable, as well.
      – Steven B. Segletes
      Nov 8 at 12:59










    • @StevenB.Segletes def is not expandable.
      – Skillmon
      Nov 8 at 13:00










    • Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
      – Steven B. Segletes
      Nov 8 at 13:01










    • @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
      – Skillmon
      Nov 8 at 13:02






    • 1




      @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
      – Skillmon
      Nov 8 at 13:05















    up vote
    7
    down vote













    All in all the same as the answer by Steven B. Segletes, but expandable. Also almost everything as contents should be fine (except the really unlikely endabr@).



    documentclass{article}

    makeatletter
    newcommandabr[1]
    {%
    abr@#1endabr@
    }
    defabr@#1#2endabr@
    {%
    #1.%
    ifrelaxdetokenize{#2}relax
    @%
    expandafter@gobble
    else
    ,%
    expandafter@firstofone
    fi
    {abr@#2endabr@}%
    }
    makeatother

    begin{document}
    Single letter:
    abr{eg}

    Multi letter:
    abr{{th}e}
    end{document}





    share|improve this answer

















    • 1




      I believe mine is fully expandable, as well.
      – Steven B. Segletes
      Nov 8 at 12:59










    • @StevenB.Segletes def is not expandable.
      – Skillmon
      Nov 8 at 13:00










    • Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
      – Steven B. Segletes
      Nov 8 at 13:01










    • @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
      – Skillmon
      Nov 8 at 13:02






    • 1




      @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
      – Skillmon
      Nov 8 at 13:05













    up vote
    7
    down vote










    up vote
    7
    down vote









    All in all the same as the answer by Steven B. Segletes, but expandable. Also almost everything as contents should be fine (except the really unlikely endabr@).



    documentclass{article}

    makeatletter
    newcommandabr[1]
    {%
    abr@#1endabr@
    }
    defabr@#1#2endabr@
    {%
    #1.%
    ifrelaxdetokenize{#2}relax
    @%
    expandafter@gobble
    else
    ,%
    expandafter@firstofone
    fi
    {abr@#2endabr@}%
    }
    makeatother

    begin{document}
    Single letter:
    abr{eg}

    Multi letter:
    abr{{th}e}
    end{document}





    share|improve this answer












    All in all the same as the answer by Steven B. Segletes, but expandable. Also almost everything as contents should be fine (except the really unlikely endabr@).



    documentclass{article}

    makeatletter
    newcommandabr[1]
    {%
    abr@#1endabr@
    }
    defabr@#1#2endabr@
    {%
    #1.%
    ifrelaxdetokenize{#2}relax
    @%
    expandafter@gobble
    else
    ,%
    expandafter@firstofone
    fi
    {abr@#2endabr@}%
    }
    makeatother

    begin{document}
    Single letter:
    abr{eg}

    Multi letter:
    abr{{th}e}
    end{document}






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 8 at 12:57









    Skillmon

    20.2k11840




    20.2k11840








    • 1




      I believe mine is fully expandable, as well.
      – Steven B. Segletes
      Nov 8 at 12:59










    • @StevenB.Segletes def is not expandable.
      – Skillmon
      Nov 8 at 13:00










    • Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
      – Steven B. Segletes
      Nov 8 at 13:01










    • @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
      – Skillmon
      Nov 8 at 13:02






    • 1




      @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
      – Skillmon
      Nov 8 at 13:05














    • 1




      I believe mine is fully expandable, as well.
      – Steven B. Segletes
      Nov 8 at 12:59










    • @StevenB.Segletes def is not expandable.
      – Skillmon
      Nov 8 at 13:00










    • Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
      – Steven B. Segletes
      Nov 8 at 13:01










    • @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
      – Skillmon
      Nov 8 at 13:02






    • 1




      @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
      – Skillmon
      Nov 8 at 13:05








    1




    1




    I believe mine is fully expandable, as well.
    – Steven B. Segletes
    Nov 8 at 12:59




    I believe mine is fully expandable, as well.
    – Steven B. Segletes
    Nov 8 at 12:59












    @StevenB.Segletes def is not expandable.
    – Skillmon
    Nov 8 at 13:00




    @StevenB.Segletes def is not expandable.
    – Skillmon
    Nov 8 at 13:00












    Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
    – Steven B. Segletes
    Nov 8 at 13:01




    Got it. I meant to say, mine can be placed in an edef. But you are right, the contents of the edef are not the final expansion.
    – Steven B. Segletes
    Nov 8 at 13:01












    @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
    – Skillmon
    Nov 8 at 13:02




    @StevenB.Segletes It can't be placed inside an edef as the edef would try to expand next before it gets defined.
    – Skillmon
    Nov 8 at 13:02




    1




    1




    @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
    – Skillmon
    Nov 8 at 13:05




    @StevenB.Segletes no. Just try edeftmp{abr{OED}} right after the definition of abr and abraux in your MWE. It'll throw an error.
    – Skillmon
    Nov 8 at 13:05










    up vote
    6
    down vote













    Here is the simplest form of my original approach. It can be placed in an edef. Its only drawback is that it can blow the stack if the argument is too long (maybe 256 characters??)



    documentclass{article}
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{#1.ifxrelax#2relax@else,abraux#2relaxfi}
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.
    end{document}


    enter image description here



    If that really were an issue, here is an alternative that doesn't have that problem.



    There seems to be a misunderstanding that this definition of abr cannot be placed into an edef. It can. Naturally, the expansion is not necessarily pretty, but it will yield the proper typesetting. The only proviso is that @MyOwnMacro is not used elsewhere in your document.



    documentclass{article}
    usepackage[T1]{fontenc}
    makeatletter
    let@MyOwnMacrorelax
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{%
    #1.ifxrelax#2relaxdef@MyOwnMacro{@}elsedef@MyOwnMacro{,abraux#2relax}fi%
    @MyOwnMacro%
    }
    makeatother
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.

    Can be edef'ed:

    edeftmp{abr{OED}} detokenizeexpandafter{tmp}

    expands to tmp
    end{document}


    enter image description here






    share|improve this answer



















    • 1




      Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
      – Sebastiano
      Nov 8 at 12:51








    • 1




      @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
      – Steven B. Segletes
      Nov 8 at 12:58










    • It can't be edefed if it is used for the first time! It'll throw an error.
      – Skillmon
      Nov 8 at 13:55










    • @Skillmon OK, letnextrelax fixes that.
      – Steven B. Segletes
      Nov 8 at 14:16






    • 2




      @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
      – Skillmon
      Nov 8 at 14:21















    up vote
    6
    down vote













    Here is the simplest form of my original approach. It can be placed in an edef. Its only drawback is that it can blow the stack if the argument is too long (maybe 256 characters??)



    documentclass{article}
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{#1.ifxrelax#2relax@else,abraux#2relaxfi}
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.
    end{document}


    enter image description here



    If that really were an issue, here is an alternative that doesn't have that problem.



    There seems to be a misunderstanding that this definition of abr cannot be placed into an edef. It can. Naturally, the expansion is not necessarily pretty, but it will yield the proper typesetting. The only proviso is that @MyOwnMacro is not used elsewhere in your document.



    documentclass{article}
    usepackage[T1]{fontenc}
    makeatletter
    let@MyOwnMacrorelax
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{%
    #1.ifxrelax#2relaxdef@MyOwnMacro{@}elsedef@MyOwnMacro{,abraux#2relax}fi%
    @MyOwnMacro%
    }
    makeatother
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.

    Can be edef'ed:

    edeftmp{abr{OED}} detokenizeexpandafter{tmp}

    expands to tmp
    end{document}


    enter image description here






    share|improve this answer



















    • 1




      Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
      – Sebastiano
      Nov 8 at 12:51








    • 1




      @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
      – Steven B. Segletes
      Nov 8 at 12:58










    • It can't be edefed if it is used for the first time! It'll throw an error.
      – Skillmon
      Nov 8 at 13:55










    • @Skillmon OK, letnextrelax fixes that.
      – Steven B. Segletes
      Nov 8 at 14:16






    • 2




      @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
      – Skillmon
      Nov 8 at 14:21













    up vote
    6
    down vote










    up vote
    6
    down vote









    Here is the simplest form of my original approach. It can be placed in an edef. Its only drawback is that it can blow the stack if the argument is too long (maybe 256 characters??)



    documentclass{article}
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{#1.ifxrelax#2relax@else,abraux#2relaxfi}
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.
    end{document}


    enter image description here



    If that really were an issue, here is an alternative that doesn't have that problem.



    There seems to be a misunderstanding that this definition of abr cannot be placed into an edef. It can. Naturally, the expansion is not necessarily pretty, but it will yield the proper typesetting. The only proviso is that @MyOwnMacro is not used elsewhere in your document.



    documentclass{article}
    usepackage[T1]{fontenc}
    makeatletter
    let@MyOwnMacrorelax
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{%
    #1.ifxrelax#2relaxdef@MyOwnMacro{@}elsedef@MyOwnMacro{,abraux#2relax}fi%
    @MyOwnMacro%
    }
    makeatother
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.

    Can be edef'ed:

    edeftmp{abr{OED}} detokenizeexpandafter{tmp}

    expands to tmp
    end{document}


    enter image description here






    share|improve this answer














    Here is the simplest form of my original approach. It can be placed in an edef. Its only drawback is that it can blow the stack if the argument is too long (maybe 256 characters??)



    documentclass{article}
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{#1.ifxrelax#2relax@else,abraux#2relaxfi}
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.
    end{document}


    enter image description here



    If that really were an issue, here is an alternative that doesn't have that problem.



    There seems to be a misunderstanding that this definition of abr cannot be placed into an edef. It can. Naturally, the expansion is not necessarily pretty, but it will yield the proper typesetting. The only proviso is that @MyOwnMacro is not used elsewhere in your document.



    documentclass{article}
    usepackage[T1]{fontenc}
    makeatletter
    let@MyOwnMacrorelax
    newcommandabr[1]{abraux#1relaxrelax}
    defabraux#1#2relax{%
    #1.ifxrelax#2relaxdef@MyOwnMacro{@}elsedef@MyOwnMacro{,abraux#2relax}fi%
    @MyOwnMacro%
    }
    makeatother
    begin{document}
    Here is abr{OED} abbreviation.

    Here is abr{XO} abbreviation.

    Can be edef'ed:

    edeftmp{abr{OED}} detokenizeexpandafter{tmp}

    expands to tmp
    end{document}


    enter image description here







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 8 at 15:31

























    answered Nov 8 at 12:50









    Steven B. Segletes

    151k9189397




    151k9189397








    • 1




      Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
      – Sebastiano
      Nov 8 at 12:51








    • 1




      @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
      – Steven B. Segletes
      Nov 8 at 12:58










    • It can't be edefed if it is used for the first time! It'll throw an error.
      – Skillmon
      Nov 8 at 13:55










    • @Skillmon OK, letnextrelax fixes that.
      – Steven B. Segletes
      Nov 8 at 14:16






    • 2




      @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
      – Skillmon
      Nov 8 at 14:21














    • 1




      Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
      – Sebastiano
      Nov 8 at 12:51








    • 1




      @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
      – Steven B. Segletes
      Nov 8 at 12:58










    • It can't be edefed if it is used for the first time! It'll throw an error.
      – Skillmon
      Nov 8 at 13:55










    • @Skillmon OK, letnextrelax fixes that.
      – Steven B. Segletes
      Nov 8 at 14:16






    • 2




      @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
      – Skillmon
      Nov 8 at 14:21








    1




    1




    Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
    – Sebastiano
    Nov 8 at 12:51






    Cheers to you :-) for your good solution. I have removed my comment. Is it correct in English language?
    – Sebastiano
    Nov 8 at 12:51






    1




    1




    @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
    – Steven B. Segletes
    Nov 8 at 12:58




    @Sebastiano 5:5 (loud and clear). Excellent English. Saluti!
    – Steven B. Segletes
    Nov 8 at 12:58












    It can't be edefed if it is used for the first time! It'll throw an error.
    – Skillmon
    Nov 8 at 13:55




    It can't be edefed if it is used for the first time! It'll throw an error.
    – Skillmon
    Nov 8 at 13:55












    @Skillmon OK, letnextrelax fixes that.
    – Steven B. Segletes
    Nov 8 at 14:16




    @Skillmon OK, letnextrelax fixes that.
    – Steven B. Segletes
    Nov 8 at 14:16




    2




    2




    @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
    – Skillmon
    Nov 8 at 14:21




    @StevenB.Segletes as soon as anything else uses next you'll get problems. In general your macro can't be fully expandable as long as it contains anything changing the definition of anything.
    – Skillmon
    Nov 8 at 14:21










    up vote
    6
    down vote













    Here's a LuaLaTeX-based solution.




    • Cases such as abr{OED} or abr{IMF} work just as expected. If the acronym contains both uppercase and lowercase letters, dots are inserted only before the uppercase letters in the interior of the acronym. E.g., abr{MSc} generates M.,Sc., and abr{PhD} generates Ph.,D..


    • It can handle mixed-case acronyms such as "PhD" directly -- no need to write abr{{Ph}D}.


    • If a "slovenly abbreviation" ends a sentence, one should place the "." punctuation mark inside the argument of abr. The code takes care to insert a @ "space factor* directive before the final . character. This, in turn, informs LaTeX that that . character should be treated as ending a sentence.


    • The code returns nothing if the argument of abr is either empty or expands to return nothing. E.g., defttt{} /abr{ttt}/ returns //. If the code encounters non-letter characters -- say, ( and ) -- no periods are inserted before or after them.


    • The code is expandable in the sense that abr can be included in the argument of an edef directive.



    enter image description here



    documentclass{article}
    usepackage{luacode} % for 'luacode' environment

    %% Lua-side code:
    begin{luacode}


    function abr ( s )
    n = string.len ( s )
    -- Do nothing unless "s" is non-empty.
    if n>0 then
    s_mod = "" -- initialize the string

    -- Process the first n-1 characters in "s"
    for i=1, n-1 do
    s12 = string.sub ( s , i, i+1 )
    s1 = string.sub ( s12, 1, 1 )
    if string.match ( s12 , "%a%u" ) then
    s_mod = s_mod .. s1 .. ".\,"
    else
    s_mod = s_mod .. s1
    end
    end

    -- Process the final character in "s"
    s_n = string.sub ( s , n)
    if string.match (s_n, "%.") then -- "." char.
    s_mod = s_mod .. "\@."
    elseif string.match (s_n, "%l") then -- lowercase letter
    s_mod = s_mod .. s_n .. ".\hbox{}"
    elseif string.match (s_n, "%u") then -- uppercase letter
    s_mod = s_mod .. s_n .. "."
    else -- Any other character:
    s_mod = s_mod .. s_n -- don't add anything after 's_n'
    end


        -- Print the modified string
    tex.sprint ( s_mod )
    end
    end

    end{luacode}

    %% LaTeX-side code: macro that calls the Lua function
    newcommandabr[2]{directlua{abr("#1")}}

    begin{document}
    abr{OED}, abr{PhD}, abr{DPhil}, abr{MSc}, abr{()}

    smallskip
    % Two calls to "abr" with an empty argument (upon expansion):
    .abr{}. quad
    defttt{} .abr{ttt}.

    bigskip
    edeftmp{abr{MA}} detokenizeexpandafter{tmp}

    edeftmp{abr{MA.}} detokenizeexpandafter{tmp}

    expands to: tmp

    smallskip
    edeftmp{abr{MSc}} detokenizeexpandafter{tmp}

    edeftmp{abr{MSc.}} detokenizeexpandafter{tmp}

    expands to: tmp

    bigskip
    Some tests of spacing after punctuation marks:

    smallskip
    a abr{PhD} candidate --- good

    a Ph.,D. candidate --- just to verify

    smallskip
    an abr{MSc} candidate --- good

    an M.,Sc. candidate --- just to verify

    smallskip
    She has a abr{PhD.} So do I. --- good

    She has a Ph.,D@. So do I. --- just to verify

    smallskip
    He has an abr{MSc.} So do I. --- good

    He has an M.,Sc. So do I. --- just to verify

    smallskip
    Does he have an abr{MSc.}? Really?! --- good

    Does he have an M.,Sc.? Really?! --- just to verify
    end{document}





    share|improve this answer























    • I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
      – Toothrot
      Nov 8 at 22:16










    • @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
      – Mico
      Nov 8 at 22:49










    • How about @ifnextchar.{spacefactor3000@gobble} or something like that?
      – Toothrot
      Nov 8 at 22:55










    • @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
      – Mico
      Nov 9 at 6:11















    up vote
    6
    down vote













    Here's a LuaLaTeX-based solution.




    • Cases such as abr{OED} or abr{IMF} work just as expected. If the acronym contains both uppercase and lowercase letters, dots are inserted only before the uppercase letters in the interior of the acronym. E.g., abr{MSc} generates M.,Sc., and abr{PhD} generates Ph.,D..


    • It can handle mixed-case acronyms such as "PhD" directly -- no need to write abr{{Ph}D}.


    • If a "slovenly abbreviation" ends a sentence, one should place the "." punctuation mark inside the argument of abr. The code takes care to insert a @ "space factor* directive before the final . character. This, in turn, informs LaTeX that that . character should be treated as ending a sentence.


    • The code returns nothing if the argument of abr is either empty or expands to return nothing. E.g., defttt{} /abr{ttt}/ returns //. If the code encounters non-letter characters -- say, ( and ) -- no periods are inserted before or after them.


    • The code is expandable in the sense that abr can be included in the argument of an edef directive.



    enter image description here



    documentclass{article}
    usepackage{luacode} % for 'luacode' environment

    %% Lua-side code:
    begin{luacode}


    function abr ( s )
    n = string.len ( s )
    -- Do nothing unless "s" is non-empty.
    if n>0 then
    s_mod = "" -- initialize the string

    -- Process the first n-1 characters in "s"
    for i=1, n-1 do
    s12 = string.sub ( s , i, i+1 )
    s1 = string.sub ( s12, 1, 1 )
    if string.match ( s12 , "%a%u" ) then
    s_mod = s_mod .. s1 .. ".\,"
    else
    s_mod = s_mod .. s1
    end
    end

    -- Process the final character in "s"
    s_n = string.sub ( s , n)
    if string.match (s_n, "%.") then -- "." char.
    s_mod = s_mod .. "\@."
    elseif string.match (s_n, "%l") then -- lowercase letter
    s_mod = s_mod .. s_n .. ".\hbox{}"
    elseif string.match (s_n, "%u") then -- uppercase letter
    s_mod = s_mod .. s_n .. "."
    else -- Any other character:
    s_mod = s_mod .. s_n -- don't add anything after 's_n'
    end


        -- Print the modified string
    tex.sprint ( s_mod )
    end
    end

    end{luacode}

    %% LaTeX-side code: macro that calls the Lua function
    newcommandabr[2]{directlua{abr("#1")}}

    begin{document}
    abr{OED}, abr{PhD}, abr{DPhil}, abr{MSc}, abr{()}

    smallskip
    % Two calls to "abr" with an empty argument (upon expansion):
    .abr{}. quad
    defttt{} .abr{ttt}.

    bigskip
    edeftmp{abr{MA}} detokenizeexpandafter{tmp}

    edeftmp{abr{MA.}} detokenizeexpandafter{tmp}

    expands to: tmp

    smallskip
    edeftmp{abr{MSc}} detokenizeexpandafter{tmp}

    edeftmp{abr{MSc.}} detokenizeexpandafter{tmp}

    expands to: tmp

    bigskip
    Some tests of spacing after punctuation marks:

    smallskip
    a abr{PhD} candidate --- good

    a Ph.,D. candidate --- just to verify

    smallskip
    an abr{MSc} candidate --- good

    an M.,Sc. candidate --- just to verify

    smallskip
    She has a abr{PhD.} So do I. --- good

    She has a Ph.,D@. So do I. --- just to verify

    smallskip
    He has an abr{MSc.} So do I. --- good

    He has an M.,Sc. So do I. --- just to verify

    smallskip
    Does he have an abr{MSc.}? Really?! --- good

    Does he have an M.,Sc.? Really?! --- just to verify
    end{document}





    share|improve this answer























    • I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
      – Toothrot
      Nov 8 at 22:16










    • @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
      – Mico
      Nov 8 at 22:49










    • How about @ifnextchar.{spacefactor3000@gobble} or something like that?
      – Toothrot
      Nov 8 at 22:55










    • @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
      – Mico
      Nov 9 at 6:11













    up vote
    6
    down vote










    up vote
    6
    down vote









    Here's a LuaLaTeX-based solution.




    • Cases such as abr{OED} or abr{IMF} work just as expected. If the acronym contains both uppercase and lowercase letters, dots are inserted only before the uppercase letters in the interior of the acronym. E.g., abr{MSc} generates M.,Sc., and abr{PhD} generates Ph.,D..


    • It can handle mixed-case acronyms such as "PhD" directly -- no need to write abr{{Ph}D}.


    • If a "slovenly abbreviation" ends a sentence, one should place the "." punctuation mark inside the argument of abr. The code takes care to insert a @ "space factor* directive before the final . character. This, in turn, informs LaTeX that that . character should be treated as ending a sentence.


    • The code returns nothing if the argument of abr is either empty or expands to return nothing. E.g., defttt{} /abr{ttt}/ returns //. If the code encounters non-letter characters -- say, ( and ) -- no periods are inserted before or after them.


    • The code is expandable in the sense that abr can be included in the argument of an edef directive.



    enter image description here



    documentclass{article}
    usepackage{luacode} % for 'luacode' environment

    %% Lua-side code:
    begin{luacode}


    function abr ( s )
    n = string.len ( s )
    -- Do nothing unless "s" is non-empty.
    if n>0 then
    s_mod = "" -- initialize the string

    -- Process the first n-1 characters in "s"
    for i=1, n-1 do
    s12 = string.sub ( s , i, i+1 )
    s1 = string.sub ( s12, 1, 1 )
    if string.match ( s12 , "%a%u" ) then
    s_mod = s_mod .. s1 .. ".\,"
    else
    s_mod = s_mod .. s1
    end
    end

    -- Process the final character in "s"
    s_n = string.sub ( s , n)
    if string.match (s_n, "%.") then -- "." char.
    s_mod = s_mod .. "\@."
    elseif string.match (s_n, "%l") then -- lowercase letter
    s_mod = s_mod .. s_n .. ".\hbox{}"
    elseif string.match (s_n, "%u") then -- uppercase letter
    s_mod = s_mod .. s_n .. "."
    else -- Any other character:
    s_mod = s_mod .. s_n -- don't add anything after 's_n'
    end


        -- Print the modified string
    tex.sprint ( s_mod )
    end
    end

    end{luacode}

    %% LaTeX-side code: macro that calls the Lua function
    newcommandabr[2]{directlua{abr("#1")}}

    begin{document}
    abr{OED}, abr{PhD}, abr{DPhil}, abr{MSc}, abr{()}

    smallskip
    % Two calls to "abr" with an empty argument (upon expansion):
    .abr{}. quad
    defttt{} .abr{ttt}.

    bigskip
    edeftmp{abr{MA}} detokenizeexpandafter{tmp}

    edeftmp{abr{MA.}} detokenizeexpandafter{tmp}

    expands to: tmp

    smallskip
    edeftmp{abr{MSc}} detokenizeexpandafter{tmp}

    edeftmp{abr{MSc.}} detokenizeexpandafter{tmp}

    expands to: tmp

    bigskip
    Some tests of spacing after punctuation marks:

    smallskip
    a abr{PhD} candidate --- good

    a Ph.,D. candidate --- just to verify

    smallskip
    an abr{MSc} candidate --- good

    an M.,Sc. candidate --- just to verify

    smallskip
    She has a abr{PhD.} So do I. --- good

    She has a Ph.,D@. So do I. --- just to verify

    smallskip
    He has an abr{MSc.} So do I. --- good

    He has an M.,Sc. So do I. --- just to verify

    smallskip
    Does he have an abr{MSc.}? Really?! --- good

    Does he have an M.,Sc.? Really?! --- just to verify
    end{document}





    share|improve this answer














    Here's a LuaLaTeX-based solution.




    • Cases such as abr{OED} or abr{IMF} work just as expected. If the acronym contains both uppercase and lowercase letters, dots are inserted only before the uppercase letters in the interior of the acronym. E.g., abr{MSc} generates M.,Sc., and abr{PhD} generates Ph.,D..


    • It can handle mixed-case acronyms such as "PhD" directly -- no need to write abr{{Ph}D}.


    • If a "slovenly abbreviation" ends a sentence, one should place the "." punctuation mark inside the argument of abr. The code takes care to insert a @ "space factor* directive before the final . character. This, in turn, informs LaTeX that that . character should be treated as ending a sentence.


    • The code returns nothing if the argument of abr is either empty or expands to return nothing. E.g., defttt{} /abr{ttt}/ returns //. If the code encounters non-letter characters -- say, ( and ) -- no periods are inserted before or after them.


    • The code is expandable in the sense that abr can be included in the argument of an edef directive.



    enter image description here



    documentclass{article}
    usepackage{luacode} % for 'luacode' environment

    %% Lua-side code:
    begin{luacode}


    function abr ( s )
    n = string.len ( s )
    -- Do nothing unless "s" is non-empty.
    if n>0 then
    s_mod = "" -- initialize the string

    -- Process the first n-1 characters in "s"
    for i=1, n-1 do
    s12 = string.sub ( s , i, i+1 )
    s1 = string.sub ( s12, 1, 1 )
    if string.match ( s12 , "%a%u" ) then
    s_mod = s_mod .. s1 .. ".\,"
    else
    s_mod = s_mod .. s1
    end
    end

    -- Process the final character in "s"
    s_n = string.sub ( s , n)
    if string.match (s_n, "%.") then -- "." char.
    s_mod = s_mod .. "\@."
    elseif string.match (s_n, "%l") then -- lowercase letter
    s_mod = s_mod .. s_n .. ".\hbox{}"
    elseif string.match (s_n, "%u") then -- uppercase letter
    s_mod = s_mod .. s_n .. "."
    else -- Any other character:
    s_mod = s_mod .. s_n -- don't add anything after 's_n'
    end


        -- Print the modified string
    tex.sprint ( s_mod )
    end
    end

    end{luacode}

    %% LaTeX-side code: macro that calls the Lua function
    newcommandabr[2]{directlua{abr("#1")}}

    begin{document}
    abr{OED}, abr{PhD}, abr{DPhil}, abr{MSc}, abr{()}

    smallskip
    % Two calls to "abr" with an empty argument (upon expansion):
    .abr{}. quad
    defttt{} .abr{ttt}.

    bigskip
    edeftmp{abr{MA}} detokenizeexpandafter{tmp}

    edeftmp{abr{MA.}} detokenizeexpandafter{tmp}

    expands to: tmp

    smallskip
    edeftmp{abr{MSc}} detokenizeexpandafter{tmp}

    edeftmp{abr{MSc.}} detokenizeexpandafter{tmp}

    expands to: tmp

    bigskip
    Some tests of spacing after punctuation marks:

    smallskip
    a abr{PhD} candidate --- good

    a Ph.,D. candidate --- just to verify

    smallskip
    an abr{MSc} candidate --- good

    an M.,Sc. candidate --- just to verify

    smallskip
    She has a abr{PhD.} So do I. --- good

    She has a Ph.,D@. So do I. --- just to verify

    smallskip
    He has an abr{MSc.} So do I. --- good

    He has an M.,Sc. So do I. --- just to verify

    smallskip
    Does he have an abr{MSc.}? Really?! --- good

    Does he have an M.,Sc.? Really?! --- just to verify
    end{document}






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 9 at 6:12

























    answered Nov 8 at 15:05









    Mico

    269k30364749




    269k30364749












    • I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
      – Toothrot
      Nov 8 at 22:16










    • @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
      – Mico
      Nov 8 at 22:49










    • How about @ifnextchar.{spacefactor3000@gobble} or something like that?
      – Toothrot
      Nov 8 at 22:55










    • @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
      – Mico
      Nov 9 at 6:11


















    • I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
      – Toothrot
      Nov 8 at 22:16










    • @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
      – Mico
      Nov 8 at 22:49










    • How about @ifnextchar.{spacefactor3000@gobble} or something like that?
      – Toothrot
      Nov 8 at 22:55










    • @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
      – Mico
      Nov 9 at 6:11
















    I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
    – Toothrot
    Nov 8 at 22:16




    I wonder if it weren't more correct to put a sentence-ending point after the macro rather than into the argument, seeing as the full-stop is not part of the abbreviation.
    – Toothrot
    Nov 8 at 22:16












    @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
    – Mico
    Nov 8 at 22:49




    @Toothrot - A major issue is: How does one inform LaTeX whether a sentence ends with a slovenly abbreviation? If one writes I like the abr{OED}., one ends up with two "dots" -- not good. The only way I can think of indicating reliably to LaTeX that a sentence ends right after some abr{...} directive is to include the period in the argument of abr. I've come up with an update to the code that allows abbr{MSc} and abr{MSc.} to be typeset differently. I'll post the updated code shortly.
    – Mico
    Nov 8 at 22:49












    How about @ifnextchar.{spacefactor3000@gobble} or something like that?
    – Toothrot
    Nov 8 at 22:55




    How about @ifnextchar.{spacefactor3000@gobble} or something like that?
    – Toothrot
    Nov 8 at 22:55












    @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
    – Mico
    Nov 9 at 6:11




    @Toothrot - Using @ifnextchar is a potentially interesting idea. I'll have to think about some more; unfortunately, I won't be able to get to work on it until this evening at the earliest. Maybe somebody else will come up with a good solution in the meantime...
    – Mico
    Nov 9 at 6:11










    up vote
    5
    down vote













    Let TeX do the recursion:



    documentclass{article}
    usepackage{xparse}
    usepackage{etoolbox}

    robustify{,} % just in order it doesn't expand in edef

    ExplSyntaxOn
    NewExpandableDocumentCommand{abr}{m}
    {
    tl_map_function:fN { tl_range:nnn { #1 } { 1 } { -2 } } __toothrot_abr:n
    tl_range:nnn { #1 } { -1 } { -1 } .
    }
    cs_generate_variant:Nn tl_map_function:nN { f }
    cs_new:Nn __toothrot_abr:n { #1., }
    ExplSyntaxOff

    begin{document}

    abr{OED}

    abr{{Ph}D}

    edeftest{abr{OED}}
    texttt{meaningtest}

    edeftest{abr{}}
    texttt{meaningtest}

    end{document}


    If a part of the argument is braced, it is considered as a single item.



    One might check whether the argument is empty in order to print nothing at all, but it doesn't seem so important a feature.



    enter image description here



    With tl_range:nnn { #1 } { 1 } { -2 } we extract all items but the last; tl_range:nnn { #1 } { -1 } { -1 } extracts the last item.






    share|improve this answer

























      up vote
      5
      down vote













      Let TeX do the recursion:



      documentclass{article}
      usepackage{xparse}
      usepackage{etoolbox}

      robustify{,} % just in order it doesn't expand in edef

      ExplSyntaxOn
      NewExpandableDocumentCommand{abr}{m}
      {
      tl_map_function:fN { tl_range:nnn { #1 } { 1 } { -2 } } __toothrot_abr:n
      tl_range:nnn { #1 } { -1 } { -1 } .
      }
      cs_generate_variant:Nn tl_map_function:nN { f }
      cs_new:Nn __toothrot_abr:n { #1., }
      ExplSyntaxOff

      begin{document}

      abr{OED}

      abr{{Ph}D}

      edeftest{abr{OED}}
      texttt{meaningtest}

      edeftest{abr{}}
      texttt{meaningtest}

      end{document}


      If a part of the argument is braced, it is considered as a single item.



      One might check whether the argument is empty in order to print nothing at all, but it doesn't seem so important a feature.



      enter image description here



      With tl_range:nnn { #1 } { 1 } { -2 } we extract all items but the last; tl_range:nnn { #1 } { -1 } { -1 } extracts the last item.






      share|improve this answer























        up vote
        5
        down vote










        up vote
        5
        down vote









        Let TeX do the recursion:



        documentclass{article}
        usepackage{xparse}
        usepackage{etoolbox}

        robustify{,} % just in order it doesn't expand in edef

        ExplSyntaxOn
        NewExpandableDocumentCommand{abr}{m}
        {
        tl_map_function:fN { tl_range:nnn { #1 } { 1 } { -2 } } __toothrot_abr:n
        tl_range:nnn { #1 } { -1 } { -1 } .
        }
        cs_generate_variant:Nn tl_map_function:nN { f }
        cs_new:Nn __toothrot_abr:n { #1., }
        ExplSyntaxOff

        begin{document}

        abr{OED}

        abr{{Ph}D}

        edeftest{abr{OED}}
        texttt{meaningtest}

        edeftest{abr{}}
        texttt{meaningtest}

        end{document}


        If a part of the argument is braced, it is considered as a single item.



        One might check whether the argument is empty in order to print nothing at all, but it doesn't seem so important a feature.



        enter image description here



        With tl_range:nnn { #1 } { 1 } { -2 } we extract all items but the last; tl_range:nnn { #1 } { -1 } { -1 } extracts the last item.






        share|improve this answer












        Let TeX do the recursion:



        documentclass{article}
        usepackage{xparse}
        usepackage{etoolbox}

        robustify{,} % just in order it doesn't expand in edef

        ExplSyntaxOn
        NewExpandableDocumentCommand{abr}{m}
        {
        tl_map_function:fN { tl_range:nnn { #1 } { 1 } { -2 } } __toothrot_abr:n
        tl_range:nnn { #1 } { -1 } { -1 } .
        }
        cs_generate_variant:Nn tl_map_function:nN { f }
        cs_new:Nn __toothrot_abr:n { #1., }
        ExplSyntaxOff

        begin{document}

        abr{OED}

        abr{{Ph}D}

        edeftest{abr{OED}}
        texttt{meaningtest}

        edeftest{abr{}}
        texttt{meaningtest}

        end{document}


        If a part of the argument is braced, it is considered as a single item.



        One might check whether the argument is empty in order to print nothing at all, but it doesn't seem so important a feature.



        enter image description here



        With tl_range:nnn { #1 } { 1 } { -2 } we extract all items but the last; tl_range:nnn { #1 } { -1 } { -1 } extracts the last item.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 8 at 13:25









        egreg

        698k8518553123




        698k8518553123






















            up vote
            5
            down vote













            documentclass{article}
            usepackage{xinttools}
            newcommandabr[1]{xintListWithSep{.,}{#1}.}
            begin{document}
            I've seen it in the abr{OED}.

            I got my abr{{Ph}D}.
            end{document}


            enter image description here



            Updated (à la Mico, but without LuaLaTeX)



            The syntax here is to use abr{PhD.} for example at end of a sentence, and abr{PhD} if not at end of a sentence.



            documentclass{article}
            usepackage{xinttools}
            makeatletter
            newcommandabr[1]
            {expandafter@gobbletworomannumeral0xintapplyunbracedabr@aux{#1}.@}
            defabr@sep{.,}
            defabr@aux#1{if.#1expandafterabr@end
            else
            if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterexpandafterexpandafterabr@sep
            fi
            fi#1}%
            defabr@end.{ abr@@end}
            defabr@@end.@{@.}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            just insert a dot in the verb|abr| argument: abr{OED.} It ended a
            sentence and in non-French spacing mode, TeX inserted the extra
            space.

            texttt{We can see it better with monospace font: abr{OED.} See?}

            I got my abr{PhD} and even my abr{PhilD}, leniency ruled
            in those days.

            texttt{The dots are added in a smart way: abr{AaaaBbbbCccc.} But it is
            assumed that the first letter is abr{Uppercased.} That's it.}

            texttt{Notice that neitger abr{Aaaa} nor abr{AaA} trigger an end of
            sentence spacing after the dot, which is abr{Good.} Isn't it?}
            end{document}


            enter image description here



            Again updated, for automatic end of sentence dot detection after abbreviation



            Here an end of sentence dot will be detected automatically.



            Of course we can't use @ifnextchar for that, as it swallows spaces.



            I added some comments about expandability, which seems to have drawn great attention in other answers :).



            documentclass{article}
            usepackage{shortvrb}MakeShortVerb{|}
            usepackage{xinttools}

            makeatletter
            protecteddefabrsep{.,}% maybe redefined even after edeffoo{abr{DPhil}}...
            protecteddefabrend{futurelet@let@tokenabr@end}
            defabr@end{ifx.@let@token@else.@fi}
            newcommandabr[1]
            {expandafter@gobbleromannumeral0xintapplyunbracedabr@aux{#1}abrend}
            defabr@aux#1{if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterabr@sep
            fi#1}%
            defabr@sep{ abrsep}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            it will detect it automatically: abr{OED}. There was no double dot.
            Besides, TeX applied its end of sentence extra space.

            texttt{We can see it better with monospace font: abr{OED}. See?}

            texttt{We can see it better with monospace font: abr{OED}, See?}

            I got a abr{MSc}, a abr{PhD} and even a abr{DPhil}. Leniency ruled
            in those days.

            {The abbreviation dots are added in a smart way, after the last
            lowercase letter following an uppercase letter:
            abr{AaaaBbbbCccc}. But it is emph{assumed} that the first letter is
            abr{Uppercased}. That's it.}

            texttt{Notice that neither abr{DPhil} nor abr{PhilD} get TeX to
            consider the inserted final dot as signaling an end of
            sentence spacing after the dot, which is abr{Good}. Isn't it?}

            About expandability, the correct way for LaTeX2e's users would be to use
            |protected@edef|, not a naked |edef|; although nowadays some
            LaTeX2e users have heard about |edef|, they might not know
            about |protected@edef|, which requires a cumbersome extra
            |makeatletter| for its usage. Anyway, none of that is described in
            textsc{Lamport} book, so I wonder if LaTeX2e users are really
            emph{allowed} into using |edef| to start with.

            But as it seems they know about |edef|, we as macro programmers need
            better to use the e-TeX's |protected| prefix and not the LaTeX2e
            |DeclareRobustCommand|, because users will not do |protected@edef|.

            This is what I have done here for a macro |abrsep| (why haven't we all
            used |abbr| by the way?) which is deliberately |protected|,
            allowing it to be redefined at location of use, long after some macro
            will have been defined via |edeffoo{abr{ABCDEFGH}}|.

            edeffoo{abr{ABCDEFGH}}texttt{stringfoo is meaningfoo}

            edeffoo{abr{AaaBccCcc}}texttt{stringfoo is meaningfoo}

            The |abrend| is also |protected|, anyway as its expansion will be
            context dependent (it detects if a dot follows), it had to not expand
            in the |edef|.
            end{document}


            enter image description here



            Notice that my proposals v2 and v3 will work only with ascii uppercase letters, no diacritics.






            share|improve this answer























            • @Mico I plagiarized your input syntax for end of sentence...
              – jfbu
              Nov 8 at 17:07






            • 1




              @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
              – jfbu
              Nov 9 at 8:21










            • Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
              – Mico
              Nov 9 at 8:39










            • (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
              – jfbu
              Nov 9 at 9:47

















            up vote
            5
            down vote













            documentclass{article}
            usepackage{xinttools}
            newcommandabr[1]{xintListWithSep{.,}{#1}.}
            begin{document}
            I've seen it in the abr{OED}.

            I got my abr{{Ph}D}.
            end{document}


            enter image description here



            Updated (à la Mico, but without LuaLaTeX)



            The syntax here is to use abr{PhD.} for example at end of a sentence, and abr{PhD} if not at end of a sentence.



            documentclass{article}
            usepackage{xinttools}
            makeatletter
            newcommandabr[1]
            {expandafter@gobbletworomannumeral0xintapplyunbracedabr@aux{#1}.@}
            defabr@sep{.,}
            defabr@aux#1{if.#1expandafterabr@end
            else
            if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterexpandafterexpandafterabr@sep
            fi
            fi#1}%
            defabr@end.{ abr@@end}
            defabr@@end.@{@.}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            just insert a dot in the verb|abr| argument: abr{OED.} It ended a
            sentence and in non-French spacing mode, TeX inserted the extra
            space.

            texttt{We can see it better with monospace font: abr{OED.} See?}

            I got my abr{PhD} and even my abr{PhilD}, leniency ruled
            in those days.

            texttt{The dots are added in a smart way: abr{AaaaBbbbCccc.} But it is
            assumed that the first letter is abr{Uppercased.} That's it.}

            texttt{Notice that neitger abr{Aaaa} nor abr{AaA} trigger an end of
            sentence spacing after the dot, which is abr{Good.} Isn't it?}
            end{document}


            enter image description here



            Again updated, for automatic end of sentence dot detection after abbreviation



            Here an end of sentence dot will be detected automatically.



            Of course we can't use @ifnextchar for that, as it swallows spaces.



            I added some comments about expandability, which seems to have drawn great attention in other answers :).



            documentclass{article}
            usepackage{shortvrb}MakeShortVerb{|}
            usepackage{xinttools}

            makeatletter
            protecteddefabrsep{.,}% maybe redefined even after edeffoo{abr{DPhil}}...
            protecteddefabrend{futurelet@let@tokenabr@end}
            defabr@end{ifx.@let@token@else.@fi}
            newcommandabr[1]
            {expandafter@gobbleromannumeral0xintapplyunbracedabr@aux{#1}abrend}
            defabr@aux#1{if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterabr@sep
            fi#1}%
            defabr@sep{ abrsep}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            it will detect it automatically: abr{OED}. There was no double dot.
            Besides, TeX applied its end of sentence extra space.

            texttt{We can see it better with monospace font: abr{OED}. See?}

            texttt{We can see it better with monospace font: abr{OED}, See?}

            I got a abr{MSc}, a abr{PhD} and even a abr{DPhil}. Leniency ruled
            in those days.

            {The abbreviation dots are added in a smart way, after the last
            lowercase letter following an uppercase letter:
            abr{AaaaBbbbCccc}. But it is emph{assumed} that the first letter is
            abr{Uppercased}. That's it.}

            texttt{Notice that neither abr{DPhil} nor abr{PhilD} get TeX to
            consider the inserted final dot as signaling an end of
            sentence spacing after the dot, which is abr{Good}. Isn't it?}

            About expandability, the correct way for LaTeX2e's users would be to use
            |protected@edef|, not a naked |edef|; although nowadays some
            LaTeX2e users have heard about |edef|, they might not know
            about |protected@edef|, which requires a cumbersome extra
            |makeatletter| for its usage. Anyway, none of that is described in
            textsc{Lamport} book, so I wonder if LaTeX2e users are really
            emph{allowed} into using |edef| to start with.

            But as it seems they know about |edef|, we as macro programmers need
            better to use the e-TeX's |protected| prefix and not the LaTeX2e
            |DeclareRobustCommand|, because users will not do |protected@edef|.

            This is what I have done here for a macro |abrsep| (why haven't we all
            used |abbr| by the way?) which is deliberately |protected|,
            allowing it to be redefined at location of use, long after some macro
            will have been defined via |edeffoo{abr{ABCDEFGH}}|.

            edeffoo{abr{ABCDEFGH}}texttt{stringfoo is meaningfoo}

            edeffoo{abr{AaaBccCcc}}texttt{stringfoo is meaningfoo}

            The |abrend| is also |protected|, anyway as its expansion will be
            context dependent (it detects if a dot follows), it had to not expand
            in the |edef|.
            end{document}


            enter image description here



            Notice that my proposals v2 and v3 will work only with ascii uppercase letters, no diacritics.






            share|improve this answer























            • @Mico I plagiarized your input syntax for end of sentence...
              – jfbu
              Nov 8 at 17:07






            • 1




              @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
              – jfbu
              Nov 9 at 8:21










            • Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
              – Mico
              Nov 9 at 8:39










            • (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
              – jfbu
              Nov 9 at 9:47















            up vote
            5
            down vote










            up vote
            5
            down vote









            documentclass{article}
            usepackage{xinttools}
            newcommandabr[1]{xintListWithSep{.,}{#1}.}
            begin{document}
            I've seen it in the abr{OED}.

            I got my abr{{Ph}D}.
            end{document}


            enter image description here



            Updated (à la Mico, but without LuaLaTeX)



            The syntax here is to use abr{PhD.} for example at end of a sentence, and abr{PhD} if not at end of a sentence.



            documentclass{article}
            usepackage{xinttools}
            makeatletter
            newcommandabr[1]
            {expandafter@gobbletworomannumeral0xintapplyunbracedabr@aux{#1}.@}
            defabr@sep{.,}
            defabr@aux#1{if.#1expandafterabr@end
            else
            if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterexpandafterexpandafterabr@sep
            fi
            fi#1}%
            defabr@end.{ abr@@end}
            defabr@@end.@{@.}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            just insert a dot in the verb|abr| argument: abr{OED.} It ended a
            sentence and in non-French spacing mode, TeX inserted the extra
            space.

            texttt{We can see it better with monospace font: abr{OED.} See?}

            I got my abr{PhD} and even my abr{PhilD}, leniency ruled
            in those days.

            texttt{The dots are added in a smart way: abr{AaaaBbbbCccc.} But it is
            assumed that the first letter is abr{Uppercased.} That's it.}

            texttt{Notice that neitger abr{Aaaa} nor abr{AaA} trigger an end of
            sentence spacing after the dot, which is abr{Good.} Isn't it?}
            end{document}


            enter image description here



            Again updated, for automatic end of sentence dot detection after abbreviation



            Here an end of sentence dot will be detected automatically.



            Of course we can't use @ifnextchar for that, as it swallows spaces.



            I added some comments about expandability, which seems to have drawn great attention in other answers :).



            documentclass{article}
            usepackage{shortvrb}MakeShortVerb{|}
            usepackage{xinttools}

            makeatletter
            protecteddefabrsep{.,}% maybe redefined even after edeffoo{abr{DPhil}}...
            protecteddefabrend{futurelet@let@tokenabr@end}
            defabr@end{ifx.@let@token@else.@fi}
            newcommandabr[1]
            {expandafter@gobbleromannumeral0xintapplyunbracedabr@aux{#1}abrend}
            defabr@aux#1{if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterabr@sep
            fi#1}%
            defabr@sep{ abrsep}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            it will detect it automatically: abr{OED}. There was no double dot.
            Besides, TeX applied its end of sentence extra space.

            texttt{We can see it better with monospace font: abr{OED}. See?}

            texttt{We can see it better with monospace font: abr{OED}, See?}

            I got a abr{MSc}, a abr{PhD} and even a abr{DPhil}. Leniency ruled
            in those days.

            {The abbreviation dots are added in a smart way, after the last
            lowercase letter following an uppercase letter:
            abr{AaaaBbbbCccc}. But it is emph{assumed} that the first letter is
            abr{Uppercased}. That's it.}

            texttt{Notice that neither abr{DPhil} nor abr{PhilD} get TeX to
            consider the inserted final dot as signaling an end of
            sentence spacing after the dot, which is abr{Good}. Isn't it?}

            About expandability, the correct way for LaTeX2e's users would be to use
            |protected@edef|, not a naked |edef|; although nowadays some
            LaTeX2e users have heard about |edef|, they might not know
            about |protected@edef|, which requires a cumbersome extra
            |makeatletter| for its usage. Anyway, none of that is described in
            textsc{Lamport} book, so I wonder if LaTeX2e users are really
            emph{allowed} into using |edef| to start with.

            But as it seems they know about |edef|, we as macro programmers need
            better to use the e-TeX's |protected| prefix and not the LaTeX2e
            |DeclareRobustCommand|, because users will not do |protected@edef|.

            This is what I have done here for a macro |abrsep| (why haven't we all
            used |abbr| by the way?) which is deliberately |protected|,
            allowing it to be redefined at location of use, long after some macro
            will have been defined via |edeffoo{abr{ABCDEFGH}}|.

            edeffoo{abr{ABCDEFGH}}texttt{stringfoo is meaningfoo}

            edeffoo{abr{AaaBccCcc}}texttt{stringfoo is meaningfoo}

            The |abrend| is also |protected|, anyway as its expansion will be
            context dependent (it detects if a dot follows), it had to not expand
            in the |edef|.
            end{document}


            enter image description here



            Notice that my proposals v2 and v3 will work only with ascii uppercase letters, no diacritics.






            share|improve this answer














            documentclass{article}
            usepackage{xinttools}
            newcommandabr[1]{xintListWithSep{.,}{#1}.}
            begin{document}
            I've seen it in the abr{OED}.

            I got my abr{{Ph}D}.
            end{document}


            enter image description here



            Updated (à la Mico, but without LuaLaTeX)



            The syntax here is to use abr{PhD.} for example at end of a sentence, and abr{PhD} if not at end of a sentence.



            documentclass{article}
            usepackage{xinttools}
            makeatletter
            newcommandabr[1]
            {expandafter@gobbletworomannumeral0xintapplyunbracedabr@aux{#1}.@}
            defabr@sep{.,}
            defabr@aux#1{if.#1expandafterabr@end
            else
            if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterexpandafterexpandafterabr@sep
            fi
            fi#1}%
            defabr@end.{ abr@@end}
            defabr@@end.@{@.}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            just insert a dot in the verb|abr| argument: abr{OED.} It ended a
            sentence and in non-French spacing mode, TeX inserted the extra
            space.

            texttt{We can see it better with monospace font: abr{OED.} See?}

            I got my abr{PhD} and even my abr{PhilD}, leniency ruled
            in those days.

            texttt{The dots are added in a smart way: abr{AaaaBbbbCccc.} But it is
            assumed that the first letter is abr{Uppercased.} That's it.}

            texttt{Notice that neitger abr{Aaaa} nor abr{AaA} trigger an end of
            sentence spacing after the dot, which is abr{Good.} Isn't it?}
            end{document}


            enter image description here



            Again updated, for automatic end of sentence dot detection after abbreviation



            Here an end of sentence dot will be detected automatically.



            Of course we can't use @ifnextchar for that, as it swallows spaces.



            I added some comments about expandability, which seems to have drawn great attention in other answers :).



            documentclass{article}
            usepackage{shortvrb}MakeShortVerb{|}
            usepackage{xinttools}

            makeatletter
            protecteddefabrsep{.,}% maybe redefined even after edeffoo{abr{DPhil}}...
            protecteddefabrend{futurelet@let@tokenabr@end}
            defabr@end{ifx.@let@token@else.@fi}
            newcommandabr[1]
            {expandafter@gobbleromannumeral0xintapplyunbracedabr@aux{#1}abrend}
            defabr@aux#1{if1ifnum`#1<`A 0fiifnum`#1>`Z 0fi1%
            expandafterabr@sep
            fi#1}%
            defabr@sep{ abrsep}
            makeatother

            begin{document}%ttfamily
            I've seen it in the abr{OED}, and if located at end of a sentence
            it will detect it automatically: abr{OED}. There was no double dot.
            Besides, TeX applied its end of sentence extra space.

            texttt{We can see it better with monospace font: abr{OED}. See?}

            texttt{We can see it better with monospace font: abr{OED}, See?}

            I got a abr{MSc}, a abr{PhD} and even a abr{DPhil}. Leniency ruled
            in those days.

            {The abbreviation dots are added in a smart way, after the last
            lowercase letter following an uppercase letter:
            abr{AaaaBbbbCccc}. But it is emph{assumed} that the first letter is
            abr{Uppercased}. That's it.}

            texttt{Notice that neither abr{DPhil} nor abr{PhilD} get TeX to
            consider the inserted final dot as signaling an end of
            sentence spacing after the dot, which is abr{Good}. Isn't it?}

            About expandability, the correct way for LaTeX2e's users would be to use
            |protected@edef|, not a naked |edef|; although nowadays some
            LaTeX2e users have heard about |edef|, they might not know
            about |protected@edef|, which requires a cumbersome extra
            |makeatletter| for its usage. Anyway, none of that is described in
            textsc{Lamport} book, so I wonder if LaTeX2e users are really
            emph{allowed} into using |edef| to start with.

            But as it seems they know about |edef|, we as macro programmers need
            better to use the e-TeX's |protected| prefix and not the LaTeX2e
            |DeclareRobustCommand|, because users will not do |protected@edef|.

            This is what I have done here for a macro |abrsep| (why haven't we all
            used |abbr| by the way?) which is deliberately |protected|,
            allowing it to be redefined at location of use, long after some macro
            will have been defined via |edeffoo{abr{ABCDEFGH}}|.

            edeffoo{abr{ABCDEFGH}}texttt{stringfoo is meaningfoo}

            edeffoo{abr{AaaBccCcc}}texttt{stringfoo is meaningfoo}

            The |abrend| is also |protected|, anyway as its expansion will be
            context dependent (it detects if a dot follows), it had to not expand
            in the |edef|.
            end{document}


            enter image description here



            Notice that my proposals v2 and v3 will work only with ascii uppercase letters, no diacritics.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 9 at 8:16

























            answered Nov 8 at 13:35









            jfbu

            44.5k65143




            44.5k65143












            • @Mico I plagiarized your input syntax for end of sentence...
              – jfbu
              Nov 8 at 17:07






            • 1




              @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
              – jfbu
              Nov 9 at 8:21










            • Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
              – Mico
              Nov 9 at 8:39










            • (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
              – jfbu
              Nov 9 at 9:47




















            • @Mico I plagiarized your input syntax for end of sentence...
              – jfbu
              Nov 8 at 17:07






            • 1




              @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
              – jfbu
              Nov 9 at 8:21










            • Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
              – Mico
              Nov 9 at 8:39










            • (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
              – jfbu
              Nov 9 at 9:47


















            @Mico I plagiarized your input syntax for end of sentence...
            – jfbu
            Nov 8 at 17:07




            @Mico I plagiarized your input syntax for end of sentence...
            – jfbu
            Nov 8 at 17:07




            1




            1




            @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
            – jfbu
            Nov 9 at 8:21




            @Mico I have again updated as I read OP is pushing towards automatic dot detection. One can not use LaTeX @ifnextchar which swallows spaces.
            – jfbu
            Nov 9 at 8:21












            Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
            – Mico
            Nov 9 at 8:39




            Outstanding! :-) Incidentally, I've gone ahead and deleted my earlier comments are they're no longer relevant, or even understandable, for readers of the current version of your answer.
            – Mico
            Nov 9 at 8:39












            (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
            – jfbu
            Nov 9 at 9:47






            (not to be told publicly: of course I could remove all usage of xinttools but where is the fun without it?) well, in fact usage of a an xinttools macro facilitates a fixed number of expansion steps to get final result, here 3 steps, I could reduce to 2 steps. But doesn't matter for an edef and anyhow the tokens of the input are subjected to full-first expansion via ifnum test etc...
            – jfbu
            Nov 9 at 9:47












            up vote
            4
            down vote













            documentclass{article}
            newcommandabr[1]{abraux#1..}
            defabraux#1#2#3{%
            #1%
            ifnum`#2>91relax% we have a lowercase letter following
            defnext{abraux#2#3}%
            else
            .ifx.#2defnext{@}else,defnext{abraux#2#3}fi
            fi
            next
            }
            begin{document}
            Here is abr{OED} abbreviation.

            Here is abr{XO} abbreviation.

            Here is abr{XOOED} abbreviation.

            abr{MSc}

            abr{DPhil}
            end{document}


            enter image description here






            share|improve this answer























            • Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
              – Mico
              Nov 9 at 6:20






            • 1




              Sure, if it is not an uppercase letter then go the next char.
              – Herbert
              Nov 9 at 19:02















            up vote
            4
            down vote













            documentclass{article}
            newcommandabr[1]{abraux#1..}
            defabraux#1#2#3{%
            #1%
            ifnum`#2>91relax% we have a lowercase letter following
            defnext{abraux#2#3}%
            else
            .ifx.#2defnext{@}else,defnext{abraux#2#3}fi
            fi
            next
            }
            begin{document}
            Here is abr{OED} abbreviation.

            Here is abr{XO} abbreviation.

            Here is abr{XOOED} abbreviation.

            abr{MSc}

            abr{DPhil}
            end{document}


            enter image description here






            share|improve this answer























            • Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
              – Mico
              Nov 9 at 6:20






            • 1




              Sure, if it is not an uppercase letter then go the next char.
              – Herbert
              Nov 9 at 19:02













            up vote
            4
            down vote










            up vote
            4
            down vote









            documentclass{article}
            newcommandabr[1]{abraux#1..}
            defabraux#1#2#3{%
            #1%
            ifnum`#2>91relax% we have a lowercase letter following
            defnext{abraux#2#3}%
            else
            .ifx.#2defnext{@}else,defnext{abraux#2#3}fi
            fi
            next
            }
            begin{document}
            Here is abr{OED} abbreviation.

            Here is abr{XO} abbreviation.

            Here is abr{XOOED} abbreviation.

            abr{MSc}

            abr{DPhil}
            end{document}


            enter image description here






            share|improve this answer














            documentclass{article}
            newcommandabr[1]{abraux#1..}
            defabraux#1#2#3{%
            #1%
            ifnum`#2>91relax% we have a lowercase letter following
            defnext{abraux#2#3}%
            else
            .ifx.#2defnext{@}else,defnext{abraux#2#3}fi
            fi
            next
            }
            begin{document}
            Here is abr{OED} abbreviation.

            Here is abr{XO} abbreviation.

            Here is abr{XOOED} abbreviation.

            abr{MSc}

            abr{DPhil}
            end{document}


            enter image description here







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 10 at 8:32

























            answered Nov 8 at 12:58









            Herbert

            265k23401712




            265k23401712












            • Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
              – Mico
              Nov 9 at 6:20






            • 1




              Sure, if it is not an uppercase letter then go the next char.
              – Herbert
              Nov 9 at 19:02


















            • Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
              – Mico
              Nov 9 at 6:20






            • 1




              Sure, if it is not an uppercase letter then go the next char.
              – Herbert
              Nov 9 at 19:02
















            Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
            – Mico
            Nov 9 at 6:20




            Can your code be extended to handle the lazy/slovenly punctuation of MSc (correct: M.,Sc.) and DPhil (correct: D.,Phil.)?
            – Mico
            Nov 9 at 6:20




            1




            1




            Sure, if it is not an uppercase letter then go the next char.
            – Herbert
            Nov 9 at 19:02




            Sure, if it is not an uppercase letter then go the next char.
            – Herbert
            Nov 9 at 19:02


















             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f458975%2frespectable-abbreviations-macro%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Schultheiß

            Liste der Kulturdenkmale in Wilsdruff

            Android Play Services Check