Quero fazer o seguinte: estou gerando um relatório que pode ser configurado para unidades imperiais ou métricas. Todos os valores estão originalmente em unidades métricas, portanto no caso de unidades imperiais todos os valores devem ser convertidos. Alguns valores podem ser N/A ou qualquer outro valor de string, caso o valor não seja aplicável. O documento é gerado automaticamente. Para conversão estou usando o pacote fp, mas o desafio é verificar a entrada. O pacote fp (e pgfmath) certamente irá errar se você tentar fazer contas com valores não numéricos. Isto é o que tenho atualmente (funciona apenas para entrada de números inteiros)
% Convert meters to inches
\newcommand{\convertmtoin}[2]
{
\if!\ifnum9<1#1!\else_\fi
\FPeval{val}{#1*39.3700787} \FPround{\val}{\val}{#2}
\else
\def\val{#1}
\fi
}
Usando pgfmath alguém poderia fazer algo assim
\newcommand{\convertmtoin}[2]
{
\pgfmathfloatparsenumber{#1}
\pgfmathfloatifflags{\pgfmathresult}{3}{\FPeval{val}{#1*39.3700787} \FPround{\val}{\val}{#2}}{\def\val{#1}}
}
Mas não consigo definir o manipulador de erros do pgfmath para gerar NaN no caso de entrada incorreta para pgfmathfloatparsenumber
\pgfkeys{/pgf/fpu/handlers/invalid number={??}{??}}
Obrigado por qualquer ajuda!
Responder1
Você também pode usar \IfDecimal
deo xstring
pacote:
Código:
\documentclass{article}
\usepackage{xstring}
\newcommand*{\CheckIfNumerical}[1]{%
\IfDecimal{#1}{%
``#1" is a number.%
}{%
``#1" is NOT a number.%
}%
}%
\begin{document}
\par\CheckIfNumerical{7}
\par\CheckIfNumerical{3.14}
\par\CheckIfNumerical{NaN}
\par\CheckIfNumerical{7. 0}
\par\CheckIfNumerical{7.0X09}
\end{document}
Responder2
ATUALIZADO para lidar com negativos.
Uma chamada para \testreal
configura um loop recursivo que verifica cada byte da string.
Primeiro, ele remove um negativo inicial, se existir, pois isso não afetará se o restante da string é ou não um número real válido.
Com o que resta, aqui está como procede. Ele observa que nenhum dígito nem ponto decimal foi encontrado na string, mas assume que é um número real válido.
Percorrendo cada byte sucessivo, o teste alternará para o estado "falha" se localizar um não-decimal e um não-dígito. O teste também falhará se encontrar duas casas decimais na string. Mas mesmo que ambos os testes sejam aprovados, ele deve ter encontrado pelo menos um dígito para passar no teste.
\documentclass[]{article}
\def\testreal#1{\def\founddigit{F}\def\itsanumber{T}\def\fndpt{F}%
\edef\tmp{\testleadneg#1\relax}%
\expandafter\testrealhelper\tmp\relax%
\if T\founddigit\itsanumber\else F\fi}
\def\testrealhelper#1#2\relax{%
\if.#1\if T\fndpt\def\itsanumber{F}\else\def\fndpt{T}\fi\else
\if1#1\FD\else
\if2#1\FD\else
\if3#1\FD\else
\if4#1\FD\else
\if5#1\FD\else
\if6#1\FD\else
\if7#1\FD\else
\if8#1\FD\else
\if9#1\FD\else
\if0#1\FD\else\def\itsanumber{F}%
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
\if\relax#2\else\testrealhelper#2\relax\fi}
\def\testleadneg#1#2\relax{\if-#1#2\else#1#2\fi}
\def\FD{\def\founddigit{T}}
\begin{document}
\testreal{just} \testreal{-just}
\testreal{123John} \testreal{-123John}
\testreal{324.56} \testreal{-324.56}
\testreal{.} \testreal{-.}
\testreal{23.4.56} \testreal{-23.4.56}
\testreal{346} \testreal{-346}
\end{document}
Responder3
datatool
fornece condicionais para testar se um argumento é numérico ou não:
\documentclass{article}
\usepackage{datatool}% http://ctan.org/pkg/datatool
\newcommand{\testreal}[1]{\ifthenelse{\DTLisnumerical{#1}}{T}{F}}
\begin{document}
\testreal{just}
\testreal{123John}
\testreal{324.56}
\testreal{.}
\testreal{23.4.56}
\testreal{346}
\end{document}
Existe \DTLisnumerical
e \DTLifnumerical
. Veja a seção2.2 condicionais ifthen(pág. 16) dodatatool
guia de usuario.
Responder4
Não entendi bem qual é sua intenção, mas aqui está um exemplo rápido de como encontrar soluções PGF.
\documentclass[]{article}
\usepackage{pgf}
\usepgflibrary{fpu}
\pgfmathdeclarefunction{m2in}{1}{%
\begingroup
\pgfkeys{/pgf/fpu}
\pgfmathfloatparsenumber{#1}
\pgfmathfloatifflags{\pgfmathresult}{3}{%True Not a number
\def\pgfmathresult{3Y0.0e0]}%
\pgfmathfloattofixed{\pgfmathresult}%
}{% False it is a number including inf
\pgfmathfloatparsenumber{#1}%
\pgfmathfloatmultiplyfixed{\pgfmathresult}{39.3700787}%
\pgfmathfloattofixed{\pgfmathresult}%
}
\pgfmathsmuggle\pgfmathresult%
\endgroup
}%
\pgfkeys{/pgf/fpu/handlers/invalid number/.code={%
\pgfmathfloatparsenumber{3Y0.0e0]}%
}
}
\begin{document}
\pgfmathfloatparsenumber{435...}% NaN
\pgfmathprintnumber[fixed]{\pgfmathresult}
\pgfmathfloatparsenumber{la la laa}% NaN
\pgfmathprintnumber[fixed]{\pgfmathresult}
\pgfmathparse{m2in(1.000)}\pgfmathprintnumber[fixed,precision=5]\pgfmathresult
\pgfmathparse{m2in(4..4)}\pgfmathresult
\end{document}
Isso vai dar
NaN
NaN
39.37007
nan