Skip to content

Cercando di ottenere [email protected] e ´minuscolo´ funzionino nel confronto tra stringhe

Questo problema può essere risolto in vari modi, ma ti mostreremo quella che per noi è la soluzione più completa.

Soluzione:

Una expl3 soluzione. Qui utilizzo il fatto che tl_map_function:nN si "mangia" gli spazi e fa una corretta piegatura delle maiuscole piuttosto che delle minuscole (si veda la documentazione Unicode per le ragioni di questa importanza):

documentclass{article}
usepackage{expl3,xparse}
ExplSyntaxOn
NewExpandableDocumentCommand compareStrings { m m +m +m }
  {
    str_if_eq:eeTF % str_if_eq_x:nnTF in older code
      { tl_map_function:fN { str_foldcase:n {#1} } use:n }
      { tl_map_function:fN { str_foldcase:n {#2} } use:n }
      {#3} {#4}
  }
cs_generate_variant:Nn tl_map_function:nN { f }
ExplSyntaxOff

begin{document}
compareStrings{test}{tesT}{1}{2}
end{document}

È necessario applicare le minuscole alle stringhe prima di confrontarle, quindi deve essere al di fuori di qualsiasi edef Qui ho usato pdfstrcmp per evitare di dover definire ulteriori macro temporanee; questa primitiva è disponibile anche in altri motori oltre a pdftex, come strcmp.

Questo trova tutti gli elementi, tranne l'ultimo, come uguali

enter image description here

documentclass{article}

%%% Support command %%%
makeatletter
newcommandcompareStrings[2]{%
edeftempA{lowercase{noexpandifnum0=noexpandpdfstrcmp
    {noexpand[email protected]#1 noexpand@empty}%
    {noexpand[email protected]#2 noexpand@empty}%
}relax}%
tempA
    expandafter@firstoftwo
  else
    expandafter@secondoftwo
  fi}

makeatother
%%%%% End support commands %%%%

begin{document}

defzz{T e sT}
0: compareStrings{tesT}{tesT}{1}{2}

1: compareStrings{test}{tesT}{1}{2}

2: compareStrings{zz}{tesT}{1}{2}

3: compareStrings{testj}{tesT}{1}{2}

end{document}

Tenere presente che lowercase non è espandibile né attiva l'espansione del suo argomento.

Pertanto, è necessario assicurarsi che i token che si espandono ai caratteri i cui casi devono essere cambiati siano già completamente espansi quando si verifica il caso lowercase o uppercase entrano in azione. (Lo stesso vale per uppercase.)

Siate consapevoli che [email protected] non attiva l'espansione del suo argomento.

Pertanto, è necessario assicurarsi che i token che si espandono ai caratteri in cui gli spazi devono essere rimossi siano già completamente espansi quando [email protected] entra in azione.

documentclass{article}
usepackage{ifthenx}

makeatletter
DeclareRobustCommandcompareStrings[2]{%
  % Make sure each instance of [email protected] gets its argument 
  % expanded - do this by edef-fing while via noexpand preventing 
  % expansion both of [email protected] and of @empty. The latter is a
  % sentinel-token for [email protected] and therefore must be let in place
  % untouched also:
  [email protected]tempA{%
    {noexpand[email protected]#1 noexpand@empty}%
    {noexpand[email protected]#2 noexpand@empty}%
  }%
  % Now that the arguments for the [email protected] are expanded,
  % via another [email protected] have carried out the [email protected]:
  [email protected]tempA{%
    % lowercase is not expandable, thus does not get expanded
    % /does not get carried out at "e-def-fing-time". 
    % Expansion of anything else but tempA is prevented via 
    % noexpand. Within tempA anything but the [email protected]
    % instances is already expanded due to the previous [email protected]
    % Thus the only effect of this [email protected] is carrying
    % out [email protected] on arguments that were expanded by 
    % the previous [email protected]
    lowercase{noexpandifthenelse{noexpandequaltempA}}%
  }%
  % Now in tempA the arguments are expanded and space tokens
  % are removed. Thus tempA expands to a call to lowercase
  % where the arguments are expanded and thus you don't have
  % control-sequence-tokens any more (whereon lowercase would have
  % no effect) but character-tokens (whereon lowwercase does have
  % an effect).
  tempA{@firstoftwo}{@secondoftwo}%
}
makeatother

parindent=0ex
parskip=baselineskip

begin{document}

verb|compareStrings{test}{tesT}{equal}{different}| yields:
compareStrings{test}{tesT}{equal}{different}

verb|compareStrings{test}{t e sT}{equal}{different}| yields:
compareStrings{test}{t e sT}{equal}{different}

verb|compareStrings{test}{t E   sT}{equal}{different}| yields:
compareStrings{test}{t e sT}{equal}{different}

verb|compareStrings{test}{tset}{equal}{different}| yields:
compareStrings{test}{tset}{equal}{different}

deftest{test}%
deftset{TsEt}%
verb|deftest{test}|\    
verb|deftset{TsEt}|

verb|compareStrings{test}{te s T}{equal}{different}| yields:
compareStrings{test}{te s T}{equal}{different}

verb|compareStrings{test}{tSeT}{equal}{different}| yields:
compareStrings{test}{tSeT}{equal}{different}

verb|compareStrings{tset}{te s T}{equal}{different}| yields:
compareStrings{tset}{te s T}{equal}{different}

verb|compareStrings{tset}{tSeT}{equal}{different}| yields:
compareStrings{tset}{tSeT}{equal}{different}

verb|compareStrings{tset}{test}{equal}{different}| yields:
compareStrings{tset}{test}{equal}{different}

verb|compareStrings{test}{tset}{equal}{different}| yields:
compareStrings{test}{tset}{equal}{different}

Be aware that verb|uppercase| and verb|lowercase| are not expandable, thus:

verb|compareStrings{uppercase{test}}{TEST}{equal}{different}| yields:
compareStrings{uppercase{test}}{TEST}{equal}{different}

verb|compareStrings{uppercase{test}}{test}{equal}{different}| yields:
compareStrings{uppercase{test}}{test}{equal}{different}

verb|compareStrings{lowercase{TEST}}{test}{equal}{different}| yields:
compareStrings{lowercase{TEST}}{test}{equal}{different}

verb|compareStrings{lowercase{test}}{test}{equal}{different}| yields:
compareStrings{lowercase{test}}{test}{equal}{different}

end{document}

enter image description here


Nel caso in cui la rimozione dei token di spazio debba essere applicata in situazioni in cui l'argomento stesso può contenere delle parentesi graffe, posso offrire una routine espandibile [email protected] per rimuovere ricorsivamente tutti i token spaziali espliciti da una sequenza di token anche quando l'argomento contiene parentesi graffe, senza bisogno di token sentinella che potrebbero non verificarsi all'interno dell'argomento.

Come effetto collaterale, la routine sostituisce le coppie di token di caratteri espliciti corrispondenti di categoria 1/2 con parentesi graffe corrispondenti.

Di solito le parentesi graffe sono gli unici caratteri con codice di categoria 1/2, quindi di solito questo non dovrebbe essere un problema. Di solito.

(Nel caso in cui qualcuno conosca un metodo che possa essere utilizzato in contesti di espansione anche su vecchi motori a 8 bit senza estensioni e-TeX o odfTeX, e in cui i token di caratteri espliciti corrispondenti della categoria 1/2 vengano lasciati intatti, sarò lieto di conoscerlo. 😉 )

documentclass{article}
usepackage{ifthenx}

makeatletter
%% Code for expandable recursive space-remove-routine:
%%
%%=============================================================================
%% Paraphernalia:
%%    [email protected], [email protected],
%%    [email protected], [email protected], [email protected]
%%    [email protected], [email protected],
%%    [email protected], [email protected]
%%=============================================================================
newcommand[email protected][2]{#1}%
newcommand[email protected][2]{#2}%
newcommand[email protected][2]{#2{#1}}%
newcommand[email protected][2]{#2#1}%
newcommand[email protected]{}[email protected]{def[email protected]}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% [email protected]{}%
%%                     {}%
%%                     {}%
%%
%% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
%% 
newcommand[email protected][1]{%
  romannumeral0expandafter[email protected]string{expandafter
  [email protected]expandafter{expandafter{string#1}expandafter
  [email protected]string}expandafter[email protected]expandafter{expandafter
  [email protected]string}expandafterexpandafter[email protected]{ }{}%
  [email protected]}{expandafterexpandafter[email protected]{ }{}[email protected]}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% [email protected]{}%
%%                      {}%
%%                      {}%
newcommand[email protected][1]{%
  romannumeral0expandafter[email protected]expandafter{expandafter{%
  string#1.}expandafter[email protected]expandafter{expandafter
  [email protected]string}expandafterexpandafter[email protected]{ }{}%
  [email protected]}{expandafterexpandafter[email protected]{ }{}[email protected]}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% [email protected]{}%
%%                             {'s 1st token is a
%%                               space-token>}%
%%                             {'s 1st token is not
%%                               a space-token>}%
newcommand[email protected][1]{%
  romannumeral0[email protected]{#1}%
  {expandafterexpandafter[email protected]{ }{}[email protected]}%
  {expandafter[email protected]string{[email protected]#1 }{}}%
}%
newcommand[email protected]{}%
longdef[email protected]#1 {%
  expandafter[email protected]expandafter{[email protected]#1{}}%
  {[email protected]{[email protected]}}{[email protected]{[email protected]}}%
  {[email protected]{ }{expandafterexpandafterexpandafterexpandafter
   expandafterexpandafterexpandafter}expandafterexpandafter
   expandafter}expandafter[email protected]expandafter{string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   [email protected]{ABCDE} yields {A}
%%
%%   [email protected]{{AB}CDE} yields {AB}
%%
%% Be aware that (La)TeX does discard preceding space tokens when
%% gathering an undelimited argument. Thus:
%%
%%   [email protected]{  ABCDE} also yields {A}
%%
%%   [email protected]{  {AB}CDE} also yields {AB}
%%
%% This routine only works when the argument of [email protected]
%% is not empty/when the argument of [email protected] does have a
%% first inner undelimited argument. Thus use this routine only in 
%% situations where non-emptiness of [email protected]'s argument is
%% ensured.
%%.............................................................................
newcommand[email protected]@SelDOm{}%
longdef[email protected]@SelDOm#1#2[email protected]{{#1}}%
newcommand[email protected][1]{%
  romannumeral0%
  [email protected]{#1[email protected]}%
}%
newcommand[email protected][1]{%
  expandafter[email protected]expandafter{[email protected]{}#1}%
  { #1}%
  {expandafter[email protected]expandafter{[email protected]@SelDOm#1}}%
}%
%%=============================================================================
%%  [email protected]{}
%%
%%  after two expansion-steps delivers 
%%  
%%  (!!! [email protected] does also replace all pairs of matching 
%%       explicit character tokens of catcode 1/2 by matching braces!!!)
%%-----------------------------------------------------------------------------
newcommand[email protected]removeallspace[1]{%
  romannumeral0[email protected]{#1}{}%
}%
newcommand[email protected][2]{%
  [email protected]{#1}{ #2}{%
    [email protected]{#1}{%
       expandafter[email protected]
       expandafter{[email protected]#1}{#2}%
    }{%
      [email protected]{#1}{%
        expandafterexpandafterexpandafter[email protected]
        expandafterexpandafterexpandafter{%
        expandafter[email protected]expandafter{%
            romannumeral0expandafter[email protected]
            romannumeral0[email protected]{#1[email protected]}{}%
        }{#2}}%
        {expandafter[email protected]expandafter{[email protected]{}#1}}%
      }{%
       expandafter[email protected]
       romannumeral0[email protected]{#1[email protected]}{#1}{#2}%
      }%
    }%
  }%
}%
newcommand[email protected][3]{%
    expandafter[email protected]
    expandafter{[email protected]{}#2}{#3#1}%
}%

%% End of code for expandable recursive space-remove-routine.
makeatother

makeatletter
DeclareRobustCommandcompareStrings[2]{%
  % Make sure each instance of [email protected] gets its argument 
  % expanded - do this by edef-fing while via noexpand preventing 
  % expansion of [email protected]:
  [email protected]tempA{%
    {noexpand[email protected]{#1}}%
    {noexpand[email protected]{#2}}%
  }%
  % Now that the arguments for the [email protected] are expanded,
  % via another [email protected] have carried out the [email protected]:
  [email protected]tempA{%
    % lowercase is not expandable, thus does not get expanded
    % /does not get carried out at "e-def-fing-time". 
    % Expansion of anything else but tempA is prevented via 
    % noexpand. Within tempA anything but the [email protected]
    % instances is already expanded due to the previous [email protected]
    % Thus the only effect of this [email protected] is carrying
    % out [email protected] on arguments that were expanded by 
    % the previous [email protected]
    lowercase{noexpandifthenelse{noexpandequaltempA}}%
  }%
  % Now in tempA the arguments are expanded and space tokens
  % are removed. Thus tempA expands to a call to lowercase
  % where the arguments are expanded and thus you don't have
  % control-sequence-tokens any more (whereon lowercase would have
  % no effect) but character-tokens (whereon lowwercase does have
  % an effect).
  tempA{[email protected]}{[email protected]}%
}
makeatother

parindent=0ex
parskip=baselineskip

begin{document}

verb|compareStrings{te{s}t}{te { S } T}{equal}{different}| yields:
compareStrings{te{s}t}{te { S } T}{equal}{different}

verb|compareStrings{test}{t E   sT}{equal}{different}| yields:
compareStrings{test}{t E   sT}{equal}{different}

verb|compareStrings{t{es}t}{t{se}t}{equal}{different}| yields:
compareStrings{t{es}t}{t{se}t}{equal}{different}

deftest{te{ s} t}%
deftset{Ts{ E }t}%
verb|deftest{te{ s} t}|\    
verb|deftset{Ts{ E }t}|

verb|compareStrings{test}{te {s} T}{equal}{different}| yields:
compareStrings{test}{te {s} T}{equal}{different}

verb|compareStrings{test}{{tS}eT}{equal}{different}| yields:
compareStrings{test}{{tS}eT}{equal}{different}

verb|compareStrings{tset}{t{e} s T}{equal}{different}| yields:
compareStrings{tset}{t{e} s T}{equal}{different}

verb|compareStrings{tset}{tS{e}T}{equal}{different}| yields:
compareStrings{tset}{tS{e}T}{equal}{different}

verb|compareStrings{tset}{test}{equal}{different}| yields:
compareStrings{tset}{test}{equal}{different}

verb|compareStrings{test}{tset}{equal}{different}| yields:
compareStrings{test}{tset}{equal}{different}

Be aware that braces are taken into account, thus:

verb|compareStrings{t{es}t}{test}{equal}{different}| yields:
compareStrings{t{es}t}{test}{equal}{different}

Be aware that verb|uppercase| and verb|lowercase| are not expandable, thus:

verb|compareStrings{uppercase{test}}{TEST}{equal}{different}| yields:
compareStrings{uppercase{test}}{TEST}{equal}{different}

verb|compareStrings{uppercase{test}}{test}{equal}{different}| yields:
compareStrings{uppercase{test}}{test}{equal}{different}

verb|compareStrings{lowercase{TEST}}{test}{equal}{different}| yields:
compareStrings{lowercase{TEST}}{test}{equal}{different}

verb|compareStrings{lowercase{test}}{test}{equal}{different}| yields:
compareStrings{lowercase{test}}{test}{equal}{different}

end{document}

enter image description here

Se sei soddisfatto di ciò che è stato esposto, hai la possibilità di lasciare una cronaca su ciò che aggiungeresti a questa sezione.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.