1
votes

Comment ajouter à une chaîne en ocaml?

Je ne sais pas comment ajouter une chaîne à lui-même en boucle.

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

mais cela donne une erreur .. Un moyen de faire ça ......?


0 commentaires

3 Réponses :


1
votes

Dans OCaml, les variables sont immuables par défaut. Vous devez utiliser une référence si vous souhaitez modifier la valeur d'une variable.

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

Voir aussi add éléments à lister dans une boucle dans OCaml .

Veuillez noter que l'ajout de deux chaînes dans OCaml est une opération O (n) (n = nombre de caractères), ce qui la rend assez coûteuse pour les chaînes longues . Vous pouvez utiliser le module Buffer pour concaténer efficacement les chaînes . L'utilisation de ^ est cependant beaucoup plus lisible.

Un bon compromis entre lisibilité et efficacité est probablement d'utiliser le module Buffer pendant longtemps et d'utiliser ^ pour les chaînes courtes. Par conséquent, utiliser un tampon pour votre itération externe serait une bonne idée. Le code se présente comme suit.

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


2 commentaires

Je dois continuer à accéder à body en tant que ! Body après la boucle for, non?


@VishalShingala Oui. Vous pouvez cependant lier! Body à un nouveau nom de variable. Même «laisser corps =! Corps entrer» fonctionnerait.



0
votes

Itérer récursivement avec un accumulateur est la manière idiomatique de faire ce que vous voulez dans ocaml:

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)

Ou mieux encore, regardez la fonction Array.fold_left.

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


0 commentaires

4
votes

L'opérateur (^) concatène deux chaînes, par exemple,

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

Si vous avez une liste de chaînes, vous pouvez utiliser la chaîne . concat , qui prend un séparateur, et une liste de chaînes et y produit une concatentation de manière efficace:

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

Pourquoi utilise le (^ ) opérateur dans un cycle est une mauvaise idée? Chaque concatentation crée une nouvelle chaîne, puis copie le contenu des deux chaînes dans la nouvelle chaîne. Ainsi, l'ajout de chaînes N aboutira à une copie d'environ n ^ 2 (où n est la longueur d'une chaîne). La même chose est vraie en Java et dans d'autres langages / bibliothèques où la concaténation renvoie une nouvelle chaîne, au lieu de muter l'un de ses arguments. Une solution habituelle consiste à utiliser le modèle StringBuilder , qui en OCaml est représenté avec le Buffer un> module. Supposons donc que vous n'ayez pas la fonction String.concat et que vous souhaitiez créer votre propre fonction de concaténation efficace (cela pourrait également être utile, car Buffer est un solution plus générale que String.concat , et fonctionnera lorsque, par exemple, vous entrez n'est pas une liste). Voici notre implémentation,

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

Cette fonction créera un tampon qui se redimensionnera automatiquement. Le 16 n'est qu'une estimation initiale et peut être n'importe quel nombre. Sur la deuxième ligne, nous parcourons simplement toutes les chaînes et poussons le dans le tampon, et enfin, nous demandons au tampon de créer la chaîne résultante. Voici comment nous utilisons cette fonction:

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


1 commentaires

S'il est vrai que l'utilisation de ^ est moins efficace que d'utiliser le module Buffer , l'utilisation du module Buffer n'est pas forcément meilleure. Le code utilisant ^ me semble plus lisible qu'un groupe d'appels à add_string , et tant que ce code n'est pas une section critique pour les performances, la lisibilité du code est plus importante que les performances .