Pergunta
Eu estou querendo saber como fazer isso em uma linguagem de programação funcional. Talvez F # ou Haskell.
Alguém pode me mostrar um exemplo sem o uso de chamadas de função exceto para find
e rfind
?
Esta função encontra a próxima barra usando i
como o num dos slash
(<0 para trás).
size_t findSlash(const char *sz, size_t i)
{
std::string s = sz;
size_t a, b, c, n, ai = abs(i), pos=0;
for (n=0; n<ai; n++)
{
if (i<0)
{
a = s.rfind("\\", pos);
b = s.rfind("/", pos);
}
else
{
a = s.find("\\", pos);
b = s.find("/", pos);
}
if (a==-1u)
{
if (b==-1u)
return pos;
c = b;
}
else if (b==-1u)
c = a;
else
c = min(a, b);
pos = c+1;
}
return c;
}
Solução
Em primeiro lugar, o código é quebrado. size_t
não está assinado tipo e nunca pode ser i<0
.
Em segundo, seu código é feio mau uso biblioteca std e ineficaz. Não deve ser usado biblioteca de expressão regular ou tal ou uso do scanner artesanal. Resultando código é muito mais limpo e mais rápido. Por exemplo (eu não tenho usado C durante muitos anos, mas o código abaixo trabalhada em 10 minutos obras.):
size_t findSlash(const char *sz, int i)
{
const char *s = sz;
if (i<0) {
for(;*s;s++);
for(;;s--){
if(s<sz) return -1;
if((*s == '/') || (*s == '\\'))
if(! ++i) break;
}
}
else {
for(;;s++){
if(! *s) return -1;
if((*s == '/') || (*s == '\\'))
if(! i--) break;
}
}
return s-sz;
}
Eu não usei para escrever Haskell ou F #, mas por exemplo o código abaixo em Erlang deve indicar como exemplo de como fazê-lo em linguagem funcional:
findslash(L, I) when is_list(L), is_integer(I) ->
if I<0 ->
case findslash(lists:reverse(L), -1*I - 1, 0) of
none -> none;
X -> length(L) - X - 1
end;
I>=0 -> findslash(L, I, 0)
end.
findslash([H|_], 0, X) when H=:=$/; H=:=$\\ -> X;
findslash([H|T], I, X) when H=:=$/; H=:=$\\ ->
findslash(T, I-1, X+1);
findslash([_|T], I, X) -> findslash(T, I, X+1);
findslash([], _, _) -> none.
Minha tentativa em Haskell com a verificação de erros e mantém a preguiça para i> = 0:
findSlash :: String -> Int -> Maybe Int
findSlash str i
| i < 0 = reversed (_findSlash (reverse str) (-1*i-1) 0)
| i >= 0 = _findSlash str i 0
where
reversed Nothing = Nothing
reversed (Just a) = Just ((length str) - a - 1)
_findSlash (x:xs) i n
| x == '/' || x == '\\' = if i==0 then Just n else _findSlash xs (i-1) (n+1)
| True = _findSlash xs i (n+1)
_findSlash [] _ _ = Nothing
Outras dicas
Haskell:
import Data.List
findSlash :: String -> Int -> Int
findSlash str i = findIndices (\c -> c == '\\' || c == '/') str !! i
Como manusear o índice negativo (o que é feio porque você realmente não quer fazê-lo):
findSlash :: String -> Int -> Int
findSlash str i =
index (findIndices (\c -> c == '\\' || c == '/') str) i
where index xs i | i < 0 = (reverse xs) !! ((-i) - 1)
| i >= 0 = xs !! i
Tratamento de erros:
findSlash :: String -> Int -> Maybe Int
findSlash str i = index i
where xs = findIndices (\c -> c == '\\' || c == '/') str
l = length xs
index i
| i < 0 && i < (-l) = Nothing
| i >= 0 && i >= l = Nothing
| i < 0 = Just $ (reverse xs) !! ((-i) - 1)
| i >= 0 = Just $ xs !! i
Agora você pode dizer:
map (findSlash "/foo/bar/baz") [-4..4]
e obter:
-- -4 -3 -2 -1 0 1 2 3 4
[Nothing,Just 0,Just 4,Just 8,Just 0,Just 4,Just 8,Nothing,Nothing]
De qualquer forma, a manipulação da deslocamento do final torna o código muito feio, e arruina a possibilidade de avaliação preguiçosa. Então eu acho que a maioria das pessoas iria usar o primeiro, talvez com um pouco de verificação de erros jogado. (Que também mata preguiça, desde comprimento seria forçar a avaliação de toda a lista. Você pode usar o "drop" em vez de "!!" a erros a evitar e para evitar a avaliação de toda a lista de resultados, no entanto. TMTOWTDI.)
Você pode escrever um código puro-funcional em puro C:
/** Return pointer to the `n`-th occurrence of any char from `chars` in `s`.
Return NULL if it can't find the `n`-th occurrence.
Start at the end of `s` if `n` is negative.
`n` is zero-based.
*/
const char*
find_nth(const char* s, int n, const char* chars)
{
if (n < 0) return rfind_nth(s, -(n+1), chars);
if (! (s && *s)) return NULL;
if (find(chars, *s)) return (n == 0) ? s : find_nth(s+1, n-1, chars);
else return find_nth(s+1, n, chars);
}
Programa completo:
#include <string.h>
const char*
find(const char* s, char c)
{
if (! (s && *s)) return NULL;
return (*s == c) ? s : find(s + 1, c);
}
const char*
rfind_nth_range(const char* s, const char* end, size_t n, const char* chars)
{
if (! (s && end && (end - s) > 0)) return NULL;
if (find(chars, *(end - 1))) // `*(end-1)` is in `chars`
return (n == 0) ? end - 1 : rfind_nth_range(s, end - 1, n-1, chars);
else
return rfind_nth_range(s, end - 1, n, chars);
}
const char*
rfind_nth(const char* s, size_t n, const char* chars)
{
return rfind_nth_range(s, s + strlen(s), n, chars);
}
int
main(void)
{
const char* const s = "ab/cd\\e";
return !(find_nth(s, 1, "/\\") == (s+5));
}
Assim, uh, o que é isso? Será que apenas encontrar a 'barra i'ésima (frente ou para trás) na cadeia (ou o' -i'th a partir do final se eu for negativa)? Eu não tenho certeza se eu interpretei isso direito apenas a partir da leitura do código.
Em qualquer caso, seria fácil para a porta, mas não está claro o que seu objetivo / propósito.