如何在 Clojure 中将 LazySeq 字符转换为字符串?

发布于 2024-08-10 21:30:51 字数 1051 浏览 4 评论 0 原文

假设我有一个 java.lang.CharacterLazySeq ,就像

(\b \ \! \/ \b \ \% \1 \9 \/ \. \i \% \$ \i \space \^@)

如何将其转换为字符串?我已经尝试过显而易见的方法

(String. my-char-seq)

,但

java.lang.IllegalArgumentException: No matching ctor found for class java.lang.String (NO_SOURCE_FILE:0)
[Thrown class clojure.lang.Compiler$CompilerException]

我认为它会抛出异常,因为 String 构造函数需要一个原始的 char[] 而不是 LazySeq 。然后我尝试了类似的方法

(String. (into-array my-char-seq))

,但它抛出了相同的异常。现在的问题是 into-array 返回一个 java.lang.Character[] 而不是原始的 char[]。这很令人沮丧,因为我实际上是这样生成字符序列的:

(map #(char (Integer. %)) seq-of-ascii-ints)

基本上我有一个代表 ASCII 字符的 ints 序列; 65 = A 等。您可以看到我明确使用了原始类型强制函数 (char x)

这意味着我的 ma​​p 函数返回原始 char,但 Clojure ma​​p 函数总体返回 java.lang。字符对象。

Let's say I have a LazySeq of java.lang.Character like

(\b \ \! \/ \b \ \% \1 \9 \/ \. \i \% \$ \i \space \^@)

How can I convert this to a String? I've tried the obvious

(String. my-char-seq)

but it throws

java.lang.IllegalArgumentException: No matching ctor found for class java.lang.String (NO_SOURCE_FILE:0)
[Thrown class clojure.lang.Compiler$CompilerException]

I think because the String constructor expects a primitive char[] instead of a LazySeq. So then I tried something like

(String. (into-array my-char-seq))

but it throws the same exception. The problem now is that into-array is returning a java.lang.Character[] instead of a primitive char[]. This is frustrating, because I actually generate my character sequence like this

(map #(char (Integer. %)) seq-of-ascii-ints)

Basically I have a seq of ints representing ASCII characters; 65 = A, etc. You can see I explicitly use the primitive type coercion function (char x).

What this means is that my map function is returning a primitive char but the Clojure map function overall is returning the java.lang.Character object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不忘初心 2024-08-17 21:30:51

这是有效的:

(apply str my-char-seq)

基本上,str 在其每个参数上调用 toString(),然后连接它们。在这里,我们使用 apply 将序列中的字符作为参数传递给 str

This works:

(apply str my-char-seq)

Basically, str calls toString() on each of its args and then concatenates them. Here we are using apply to pass the characters in the sequence as args to str.

乜一 2024-08-17 21:30:51

另一种方法是使用 clojure.string/join,如下所示:

(require '[clojure.string :as str] )
(assert (= (vec "abcd")                [\a \b \c \d] ))
(assert (= (str/join  (vec "abcd"))    "abcd" ))
(assert (= (apply str (vec "abcd"))    "abcd" ))

clojure.string/join 有另一种形式,它接受分隔符。请参阅:

http://clojuredocs.org/clojure_core/clojure.string/join

了解更多信息复杂的问题,您可能还希望查看 Tupelo 库中的 strcat

(require '[tupelo.core :as t] )
(prn (t/strcat "I " [ \h \a nil \v [\e \space (byte-array [97])
                  [ nil 32 "complicated" (Math/pow 2 5) '( "str" nil "ing") ]]] ))
;=> "I have a complicated string"

Another way is to use clojure.string/join, as follows:

(require '[clojure.string :as str] )
(assert (= (vec "abcd")                [\a \b \c \d] ))
(assert (= (str/join  (vec "abcd"))    "abcd" ))
(assert (= (apply str (vec "abcd"))    "abcd" ))

There is an alternate form of clojure.string/join which accepts a separator. See:

http://clojuredocs.org/clojure_core/clojure.string/join

For more complicated problems, you may also wish to lookat strcat from the Tupelo library:

(require '[tupelo.core :as t] )
(prn (t/strcat "I " [ \h \a nil \v [\e \space (byte-array [97])
                  [ nil 32 "complicated" (Math/pow 2 5) '( "str" nil "ing") ]]] ))
;=> "I have a complicated string"
熟人话多 2024-08-17 21:30:51

作为一种特殊情况,如果相关序列的基础类型是 clojure.lang.StringSeq ,您也可以这样做:

(.s (my-seq))

这非常高效,因为它只是从 clojure 中提取公共最终 CharSequence 字段StringSeq 类。

示例:

(type (seq "foo"))
=> clojure.lang.StringSeq

(.s (seq "foo"))
=> "foo"

(type (.s (seq "foo")))
=> java.lang.String

时序影响的示例(并注意使用类型提示时的差异):

(time 
  (let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
    (dotimes [_ 1000000]
      (apply str q))))
"Elapsed time: 620.943971 msecs"
=> nil

(time 
  (let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
    (dotimes [_ 1000000]
      (.s q))))
"Elapsed time: 1232.119319 msecs"
=> nil

(time 
  (let [^StringSeq q (seq "xxxxxxxxxxxxxxxxxxxx")]
    (dotimes [_ 1000000]
      (.s q))))
"Elapsed time: 3.339613 msecs"
=> nil

As a special case, if the underlying type of the sequence in question is clojure.lang.StringSeq you can also do:

(.s (my-seq))

which is extremely performant as it is just pulling out the public final CharSequence field from the clojure StringSeq class.

Example:

(type (seq "foo"))
=> clojure.lang.StringSeq

(.s (seq "foo"))
=> "foo"

(type (.s (seq "foo")))
=> java.lang.String

an example of the timing implications (and note the difference when using a type hint):

(time 
  (let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
    (dotimes [_ 1000000]
      (apply str q))))
"Elapsed time: 620.943971 msecs"
=> nil

(time 
  (let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
    (dotimes [_ 1000000]
      (.s q))))
"Elapsed time: 1232.119319 msecs"
=> nil

(time 
  (let [^StringSeq q (seq "xxxxxxxxxxxxxxxxxxxx")]
    (dotimes [_ 1000000]
      (.s q))))
"Elapsed time: 3.339613 msecs"
=> nil
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文