如何在ocaml中附加字符串?

时间:2019-02-04 13:23:10

标签: ocaml

我不知道如何在循环中向自身添加一些字符串。

let parameters = [| [| ("name", "fdjks"); ("value", "dsf") |]; [| ("name", "&^%"); ("value", "helo") |] |] ;;
let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";;
let body = "";;

for x = 0 to (Array.length(parameters) : int)-1 do
    let (_, paramName) = parameters.(x).(0) in
    let (_, paramValue) = parameters.(x).(1) in
    body = body ^ "--" ^ boundary ^ "\r\n" ^ "Content-Disposition:form-data; name=\"" ^ paramName ^ "\"\r\n\r\n" ^ paramValue ;
    print_endline(body)
done;;

但这会出错。 有什么办法...?

3 个答案:

答案 0 :(得分:1)

(^)运算符连接两个字符串,例如,

# "hello" ^ ", " ^ "world!";;  
- : string = "hello, world!"

如果您有一个字符串列表,则可以使用String.concat函数,该函数带有一个分隔符和一个字符串列表,并以有效的方式在其中产生连接:

# String.concat ", " ["hello"; "world"];;
- : string = "hello, world"

为什么在循环中使用(^)运算符是一个坏主意?每次合并都会创建一个新字符串,然后将两个字符串的内容复制到新字符串中。因此,追加N字符串将最终导致大约n^2的复制(其中n是字符串的长度)。在Java和其他语言/库中,连接返回一个新的字符串,而不是改变其参数之一,也是如此。通常的解决方案是使用StringBuilder pattern,它在OCaml中用Buffer模块表示。因此,假设您没有String.concat函数,并且您想构建自己的有效串联函数(这也可能很有用,因为Buffer比{{1}是更通用的解决方案},并且可以在例如您输入的不是列表时使用)。这是我们的实现,

String.concat

此函数将创建一个缓冲区,该缓冲区将自动调整其大小。 let concat xs = let buf = Buffer.create 16 in List.iter (Buffer.add_string buf) xs; Buffer.contents buf 只是一个初步的猜测,可以是任何数字。在第二行中,我们仅遍历所有字符串并将其推入缓冲区,最后,我们要求缓冲区构建结果字符串。这是我们使用此功能的方式:

16

答案 1 :(得分:0)

在OCaml中,变量默认是不可变的。如果要更改变量的值,则需要使用引用。

let parameters = [| [| ("name", "fdjks"); ("value", "dsf") |]; [| ("name", "&^%"); ("value", "helo") |] |] ;;
let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";;
let body = ref "";;

for x = 0 to (Array.length(parameters) : int)-1 do
    let (_, paramName) = parameters.(x).(0) in
    let (_, paramValue) = parameters.(x).(1) in
    body := !body ^ "--" ^ boundary ^ "\r\n" ^ "Content-Disposition:form-data; name=\"" ^ paramName ^ "\"\r\n\r\n" ^ paramValue ;
    print_endline(!body)
done;;       

另请参阅add elements to list in a loop in OCaml

请注意,在OCaml中添加两个字符串是O(n)操作(n =字符数),这对于长字符串而言相当昂贵。您可以使用Buffer module有效地连接字符串。但是,使用^更具可读性。

长时间使用Buffer模块和对短字符串使用^可能在可读性和效率之间做出了很好的折衷。因此,为外部迭代使用Buffer是一个好主意。代码如下。

let parameters = [| [| ("name", "fdjks"); ("value", "dsf") |];
                    [| ("name", "&^%"); ("value", "helo") |] |] ;;
let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";;
let body = Buffer.create 256;;

for x = 0 to (Array.length(parameters) : int)-1 do
  let (_, paramName) = parameters.(x).(0) in
  let (_, paramValue) = parameters.(x).(1) in
  Buffer.add_string body
                    ("--" ^ boundary ^ "\r\n"
                     ^ "Content-Disposition:form-data; name=\""
                     ^ paramName ^ "\"\r\n\r\n" ^ paramValue);
  print_endline(Buffer.contents body)
done;;

答案 2 :(得分:0)

使用累加器递归迭代是在ocaml中执行所需操作的惯用方式:

let parameters = [| [| ("name", "fdjks"); ("value", "dsf") |]; [| ("name", "&^%"); "value", "helo") |] |] ;;
let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW" ;;
let len = Array.length(parameters) ;;

let rec loop accum index =
  if index < len then
    let (_, paramName) = parameters.(index).(0) in
    let (_, paramValue) = parameters.(index).(1) in
    loop (accum ^ "--" ^ boundary ^ "\r\n"
          ^ "Content-Disposition:form-data; name=\""
          ^ paramName ^ "\"\r\n\r\n" ^ paramValue)
         (index + 1)
  else print_endline accum
  in
  loop "" 0 ;;

或者最好还是看看Array.fold_left函数。

let parameters = [| [| ("name", "fdjks"); ("value", "dsf") |]; [| ("name", "&^%"); ("value", "helo") |] |] ;;
let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";;

let () = print_endline
           (Array.fold_left
              (fun acc elt ->
                let (_, paramName) = elt.(0) in
                let (_, paramValue) = elt.(1) in
                acc ^ "--" ^ boundary ^ "\r\n"
                ^ "Content-Disposition:form-data; name=\""
                ^ paramName ^ "\"\r\n\r\n" ^ paramValue)
              ""
              parameters)