题
我想知道如何在一个函数式编程语言做到这一点。也许F#或哈斯克尔。
有人能告诉我一个例子,而无需使用除了find
和rfind
任何函数调用?
此函数查找使用i
作为slash
(<0为向后)的NUM下一个斜线。
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;
}
解决方案
在第一,您的代码被打破了。 size_t
是无符号类型决不可i<0
。
在第二,代码是难看的std库滥用和无效的。应该使用正则表达式库或这样或使用手工制作的扫描仪。最终的代码更干净,更快速。例如(我还没有被用C多年,但低于10分钟制作的代码的工作。):
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;
}
我还没有用于写的Haskell或F#,但是例如低于代码二郎应为例说明如何做到这一点在功能性的语言:
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.
我在Haskell尝试与错误检查,并保持懒惰对于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
其他提示
Haskell中:
import Data.List
findSlash :: String -> Int -> Int
findSlash str i = findIndices (\c -> c == '\\' || c == '/') str !! i
处理负指数(这是丑陋的,因为你真的不希望这样做):
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
处理错误:
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
现在你可以说:
map (findSlash "/foo/bar/baz") [-4..4]
和得到:
-- -4 -3 -2 -1 0 1 2 3 4
[Nothing,Just 0,Just 4,Just 8,Just 0,Just 4,Just 8,Nothing,Nothing]
总之,处理从端部偏移使得代码很丑陋,和废墟为惰性计算的可能性。所以,我想大多数人都会使用第一个,也许有一点点错误检查扔了进去。(这也杀死了懒惰,因为长度会迫使整个列表的评价。你可以用“滴”代替“!”以避免发生错误,并且防止整个结果列表的评价,但是。TMTOWTDI。)
可以写在纯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);
}
完整方案:
#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));
}
所以,呃,这是什么?是否只要找到“第i个斜杠(向前或向后)的字符串(或”从最终-i'th如果我是负的)?我不知道如果我理解正确刚刚从阅读的代码。
在任何情况下,这将是直接的端口,但目前尚不清楚你的目标/目的是什么。
不隶属于 StackOverflow