Как добавить в строку в ocaml? - PullRequest
0 голосов
/ 04 февраля 2019

Я не знаю, как добавить в себя некоторую строку в цикле.

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 голосов
/ 04 февраля 2019

Рекурсивная итерация с аккумулятором - это идиоматический способ сделать то, что вы хотите в 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)
0 голосов
/ 04 февраля 2019

Оператор (^) объединяет две строки, например,

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

Если у вас есть список строк, вы можете использовать функцию String.concat, которая принимает разделитель, и списокстроит и производит там конкатенацию эффективным способом:

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

Почему использование оператора (^) в цикле - плохая идея?Каждая конкатенация создает новую строку, а затем копирует содержимое обеих строк в новую строку.Таким образом, добавление N строк приведет к приблизительно n^2 копированию (где n - длина строки).То же самое верно для Java и других языков / библиотек, где конкатенация возвращает новую строку вместо изменения одного из ее аргументов.Обычное решение - использовать шаблон StringBuilder , который в OCaml представлен модулем Buffer .Предположим, у вас нет функции String.concat, и вы хотели бы создать свою собственную эффективную функцию конкатенации (это также может быть полезно, поскольку Buffer является более общим решением, чем String.concat, и будет работать, когдаНапример, вы вводите не список).Вот наша реализация,

let concat xs =
  let buf = Buffer.create 16 in
  List.iter (Buffer.add_string buf) xs;
  Buffer.contents buf

Эта функция создаст буфер, который автоматически изменит свой размер.16 - это только начальное предположение и может быть любым числом.Во второй строке мы просто перебираем все строки и помещаем их в буфер, и, наконец, просим буфер сформировать полученную строку.Вот как мы используем эту функцию:

# concat ["hello"; ", "; "world"];;
- : string = "hello, world" 
0 голосов
/ 04 февраля 2019

В 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;;       

См. Также добавить элементы в список в цикле в OCaml .

Обратите внимание, что добавление двух строк в OCaml является операцией O (n) (n = количество символов), что делает его довольно дорогим для длинных строк.Вы можете использовать Буферный модуль для эффективного объединения строк.Однако использование ^ гораздо удобнее для чтения.

Хороший компромисс между удобочитаемостью и эффективностью, вероятно, заключается в использовании модуля 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;;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...