11

I have a predefined command \mycommand which, for some reason, outputs {"/home/user/di rect ory/"/}. (Yes, there's a slash after the quotation mark, and there are curly braces.) Could one think of a one-liner or the simplest possible TeX/LaTeX code to remove the quotation marks, and possibly also the curly braces so that what remains is /home/user/di rect ory//?

No additional package loading, please.

 \def\mycommand{{"/home/user/di rect ory/"/}}

EDIT: The command turned out to be \def\mycommand{{\string "/home/user/di rect ory/\string "/}} when the path contained spaces, and \def\mycommand{{/home/user/directory//}} otherwise. Still looking for an elegant way of extracting the path.

6
  • 2
    Can you add a minimal example?
    – egreg
    Commented Aug 6, 2015 at 11:08
  • This is a string that LyX outputs while compiling the documents, it's called \input@path there and is constructed as follows os << "\\makeatletter\n" << "\\def\\input <at> path{{" << docdir << "/}}\n" << "\\makeatother\n"; Commented Aug 6, 2015 at 11:11
  • So I guess \def\mycommand{{"/home/user/di rect ory/"/}} would be the definition in my case. Commented Aug 6, 2015 at 11:19
  • 1
    Any particular reason for wishing to prohibit the use of packages?
    – Mico
    Commented Aug 6, 2015 at 11:29
  • I want to use it in a hack that won't have too much code scattered around. And since I'm only removing the quotation marks, I thought there might be a simple low level solution. Until LyX fixes this as I think it's a bug. Commented Aug 6, 2015 at 11:43

4 Answers 4

10

Curly braces

An one-liner to remove the curly braces:

\expandafter\def\expandafter\mycommand\mycommand

Explanation:
\mycommand contains {"/home/user/di rect ory/"/}. When the \expandafter commands have done their job, the following remains:

\def\mycommand{"/home/user/di rect ory/"/}

The curly braces are now used for the definition text.

Quotes

Another one-liner to remove the quotes:

\def\x"#1"{#1}\edef\mycommand{\expandafter\x\mycommand}

Result of \show\mycommand:

> \mycommand=macro:
->/home/user/di rect ory//.

Explanation:
Macro \x is defined as macro which expects a delimited argument with the quote as delimiting token. The argument is returned without the quotes. \edef expands the definition text. After the expansion of \expandafter:

\edef\mycommand{\x"/home/user/di rect ory/"/}

After the expansion of \x:

\edef\mycommand{/home/user/di rect ory//}

Then nothing is left for expansion and \edef defines the macro like \def.

0
4

Here's a LuaLaTeX-based solution. A LaTeX macro called \DeleteQuotes is set up, which removes all " characters from its argument. No assumption is imposed or required regarding either the location or the number of " characters in the argument of \DeleteQuotes. In particular, no difficulty arises if the argument of \DeleteQuotes contains no " characters at all. (Incidentally, as long as the curly braces are balanced in both number and ordering, they are automatically removed by TeX.)

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}  
\usepackage{luacode}

%% Lua-side code  
\begin{luacode}
function delete_quotes ( s )
   s = string.gsub ( s, '"', '')
   tex.sprint ( s )
end
\end{luacode}

%% TeX-side code
\newcommand\DeleteQuotes[1]{\directlua{delete_quotes(\luastring{#1})}}

\begin{document}

\newcommand\MyCommand{{"/home/user/di rect ory/"/}}
\DeleteQuotes{\MyCommand}

\end{document}
2

This assumes the format of the token list is

{..."..."...}

The \normalize macro receives as a mandatory argument the token list to normalize, possibly in “stored” form. The optional argument should be a control sequence that will receive the normalized string as replacement text (no check about it being defined is performed). If no optional argument is given, the mandatory argument should be a control sequence storing the string, which will be redefined.

\documentclass{article}

\makeatletter
\newcommand{\normalize}{\@dblarg\norm@lize}
\def\norm@lize[#1]#2{%
  \expandafter\expandafter\expandafter
  \remove@quotes
  \expandafter
  \@firstofone#2\remove@quotes{#1}%
}
% remove the last #3 in the following if you want to remove
% the tokens after the second quote symbol
\def\remove@quotes#1"#2"#3\remove@quotes#4{\def#4{#1#2#3}}
\makeatother

\def\mycommand{{"/home/user/di rect ory/"/}}

\normalize[\tmp]{\mycommand}\show\tmp

\normalize{\mycommand}\show\mycommand

\normalize[\another]{{"/home/user/di rect ory/"/}}\show\another

\stop

Here's the output on the terminal:

> \tmp=macro:
->/home/user/di rect ory//.
l.18 \normalize[\tmp]{\mycommand}\show\tmp

? 
> \mycommand=macro:
->/home/user/di rect ory//.
l.20 \normalize{\mycommand}\show\mycommand

? 
> \another=macro:
->/home/user/di rect ory//.
l.22 ...{"/home/user/di rect ory/"/}}\show\another

? 

If the code \def#4{#1#2#3} is changed to \def#4{#1#2}, the tokens after the closing quote are discarded and the output on the terminal is

> \tmp=macro:
->/home/user/di rect ory/.
l.18 \normalize[\tmp]{\mycommand}\show\tmp

? 
> \mycommand=macro:
->/home/user/di rect ory/.
l.20 \normalize{\mycommand}\show\mycommand

? 
> \another=macro:
->/home/user/di rect ory/.
l.22 ...{"/home/user/di rect ory/"/}}\show\another

? 

Now that the input format seems to be fully known, here's a different solution for both cases.

\documentclass{article}

\makeatletter
\newcommand\extractrealpath{\@dblarg\extract@real@path}
\def\extract@real@path[#1]#2{%
  % remove the braces and stringify the quotes
  \edef\erp@temp{\expandafter\@firstofone#2}%
  % remove the trailing slash
  \expandafter\erp@remove@slash\erp@temp\@nil
  \erp@remove@quotes
  \let#1\erp@temp
}
\def\erp@remove@slash#1/\@nil{%
  \def\erp@temp{#1}%
}
\begingroup\catcode`\"=12
\gdef\erp@remove@quotes{\expandafter\erp@remove@quotes@aux\erp@temp""\@nil}
\gdef\erp@remove@quotes@aux#1"#2"#3\@nil{%
  \ifx\hfuzz#2\hfuzz
    % no quotes
    \def\erp@temp{#1}%
  \else
    \def\erp@temp{#2}%
  \fi
}
\endgroup
\makeatother

\begin{document}

\def\mycommand{{\string "/home/user/di rect ory/\string "/}}
\extractrealpath[\saved]\mycommand

\texttt{\saved}

\def\mycommand{{/home/user/directory//}}
\extractrealpath\mycommand

\texttt{\mycommand}

\end{document}

enter image description here

7
  • Thanks egreg. Now that I learned about \show and tested on the real problem things got even more complicated. What LyX has for \input@path is macro:->{\string "/home/user/di rect ory/\string "/} in case the path has spaces in it, and macro:->{/home/user/directory//} otherwise. Your thoughts? @HeikoOberdiek Commented Aug 6, 2015 at 14:44
  • 1
    @PhilipPirrip Just do \edef\input@path{\input@path}.
    – Manuel
    Commented Aug 6, 2015 at 15:18
  • 1
    @PhilipPirrip If you need to distinguish two cases as described in your comment then you can do it by one-line code: \bgroup \def\string#1{}\expandafter\xdef\expandafter\input@path\input@path\egroup.
    – wipet
    Commented Aug 7, 2015 at 4:54
  • 1
    @wipet Well, not \def\string
    – egreg
    Commented Aug 7, 2015 at 8:26
  • 1
    @PhilipPirrip Added new code
    – egreg
    Commented Aug 7, 2015 at 9:21
1

First time I play with this kind of things, so probably it's not right. I let everyone correct this answer if he wants.

A four liner.

It's a completely expandable solution, and the \edef part is there to show two things: first, that it's completely expandable, and second, so that the \detokenize shows that the { and } are not in the result.

\documentclass{scrartcl}

\def\endremovequotes{\endremovequotes}
\def\removequotes#1{\expandafter\doremovequotes#1"\endremovequotes"}
\def\doremovequotes#1{\dodoremovequotes#1}
\def\dodoremovequotes#1"{\ifx\endremovequotes#1\empty\else#1\expandafter\dodoremovequotes\fi}

\def\tmp{{"/home/user/di rect ory/"/}}

\begin{document}

\removequotes\tmp

\edef\tmp{\removequotes\tmp}
\texttt{\detokenize\expandafter{\tmp}}

\end{document}

A three liner :)

\def\removequotes#1{\expandafter\doremovequotes#1"\relax}
\def\doremovequotes#1{\dodoremovequotes#1}
\def\dodoremovequotes#1"#2\relax{\if\relax\detokenize{#2}\relax\csname @gobble\expandafter\endcsname\else\csname @firstofone\expandafter\endcsname\fi{#1\dodoremovequotes#2\relax}}

Old definition

\makeatletter
\newcommand*\removequotes[1]{\expandafter\doremovequotes#1}
\def\doremovequotes#1{\ifquotein{#1}{\removeonequote{#1}}{#1}}
\def\ifquotein#1{\doifquotein#1""\relax}
\def\doifquotein#1"#2"\relax%
  {\if\relax\detokenize{#2}\relax
   \expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi}
\def\removeonequote#1{\doremoveonequote#1\relax}
\def\doremoveonequote#1"#2\relax{\doremovequotes{#1#2}}
\makeatother

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .