在OCaml中如何将字符添加到字符串中?

10

标准库中似乎没有类型为char -> string -> string的函数,可以将一个char插入到string的前面(或末尾)。有一些解决方法,比如使用String.makeString.blit。是否有更优雅的方法来实现这个功能?


1
使用 Buffer 对于增长字符串可能更加合适。 - Basile Starynkevitch
3个回答

19

@pad的代码是我会使用的,因为如果可能的话,我喜欢将字符串视为不可变的。但我不会使用Char.escaped;它是专门用于当您想要字符的OCaml词法表示时。因此,如果进行更改,您将获得以下结果:

let prefix_char s c = String.make 1 c ^ s

let suffix_char s c = s ^ String.make 1 c

更新

自从这个问题被提出以来的这些年里,OCaml已经发生了变化,使得字符串是不可变的。非常好。


9

String.makeString.blit是一种不错的方法,但它们似乎是命令式的。个人更喜欢使用Char.escaped和字符串连接来创建中缀函数:

let (^$) c s = s ^ Char.escaped c (* append *)
let ($^) c s = Char.escaped c ^ s (* prepend *)

8
我认为Char.escaped适用于生成OCaml代码输出或编写可读性强的消息等专业用途。对于普通情况,String.make 1 c可能是您想要的。它似乎有点笨拙。Batteries库中有BatString.of_char - Jeffrey Scofield
1
感谢对Char.escaped的澄清。我将保持答案不变,以便其他人了解它。 - pad
2
为什么在 Jeffrey Scofield 的回答和评论中已经解释清楚了,却被踩了? - pad

8
我比较了不同方法的效率:
  1. I wrote a simple test:

    let append_escaped s c = s ^ Char.escaped c
    let append_make    s c = s ^ String.make 1 c
    let append_sprintf s c = Printf.sprintf "%s%c" s c
    
    let _ =
      let s = "some text" in
      let c = 'a' in
      for i = 1 to 100000000 do
        let _ = append_(*escaped|make|sprintf*) s c in ()
      done
    
  2. I compiled it natively (Intel Core 2 Duo).

  3. I ran the test three times for each option, timing it with time, and calculating the mean real time elapsed.

以下是结果:
  1. s ^ String.make 1 c:7.75秒(100%

  2. s ^ Char.escaped c:8.30秒(107%

  3. Printf.sprintf "%s%c" s c:68.57秒(885%


2
再次提醒:Char.escapedString.make的功能不同。它根据OCaml的词法规则为字符创建一个“转义”值。如果要尝试通过这种方式添加换行符('\n'),就会看到这一点。这也是为什么它稍微慢一些的原因。对于大多数一般用途,您应该使用String.make 1 c。当然,Printf.sprintf速度要慢得多,但非常灵活。 - Jeffrey Scofield
@JeffreyScofield 我只是想补充一下,这样人们就不需要自己尝试了:Char.escaped '\n' = "\\n" - Rok Strniša
谢谢,也许我应该自己说这句话!这些评论被限制为非常短的。无论如何:Char.escaped '\n'会给你一个由'\\''n'组成的两个字符的字符串。String.make 1 '\n'会给你一个由'\n'组成的一个字符的字符串,这更可能是你想要的。 - Jeffrey Scofield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接