Как получить набор всех букв в Java / Clojure?

в Python, я могу сделать это:

>>> import string
>>> string.letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

есть ли способ сделать что-то подобное в Clojure (кроме копирования и вставки вышеуказанных символов где-нибудь)? Я просмотрел как стандартную библиотеку Clojure, так и стандартную библиотеку java и не смог ее найти.

8 ответов


правильно не ориентированная на ASCII реализация:

private static String allLetters(String charsetName)
{
    CharsetEncoder ce = Charset.forName(charsetName).newEncoder();
    StringBuilder result = new StringBuilder();
    for(char c=0; c<Character.MAX_VALUE; c++)
    {
        if(ce.canEncode(c) && Character.isLetter(c))
        {
            result.append(c);
        }
    }
    return result.toString();
}

вызовите это с помощью "US-ASCII", и вы получите желаемый результат (за исключением того, что заглавные буквы идут первыми). Вы можете назвать это с Charset.defaultCharset(), но я подозреваю, что вы получите гораздо больше, чем буквы ASCII в большинстве систем, даже в США.

предостережение: рассматривает только основную многоязычную плоскость. Было бы не слишком сложно распространить на дополнительные плоскости, но это займет намного больше времени, и утилита сомнительный.


Если вы просто хотите Ascii символов,

(map char (concat (range 65 91) (range 97 123)))

даст

(\A \B \C \D \E \F \G \H \I \J \K \L \M \N \O \P \Q \R \S \T \U \V \W \X \Y \Z 
 \a \b \c \d \e \f \g \h \i \j \k \l \m \n \o \p \q \r \s \t \u \v \w \x \y \z)

основываясь на императивном Java-решении Michaels, это идиоматическое (ленивые последовательности) решение Clojure:

(ns stackoverflow
  (:import (java.nio.charset Charset CharsetEncoder)))

(defn all-letters [charset]
  (let [encoder (. (Charset/forName charset) newEncoder)]
    (letfn [(valid-char? [c]
             (and (.canEncode encoder (char c)) (Character/isLetter c)))
        (all-letters-lazy [c]
                  (when (<= c (int Character/MAX_VALUE))
                (if (valid-char? c)
                  (lazy-seq
                   (cons (char c) (all-letters-lazy (inc c))))
                  (recur (inc c)))))]
      (all-letters-lazy 0))))

обновление: Спасибо cgrand за это предпочтительное решение высокого уровня:

(defn letters [charset-name]
  (let [ce (-> charset-name java.nio.charset.Charset/forName .newEncoder)]
    (->> (range 0 (int Character/MAX_VALUE)) (map char)
         (filter #(and (.canEncode ce %) (Character/isLetter %))))))

но сравнение performace между моим первым подходом

user> (time (doall (stackoverflow/all-letters "ascii"))) 
"Elapsed time: 33.333336 msecs"                                                  
(\A \B \C \D \E \F \G \H \I \J \K \L \M \N \O \P \Q \R \S \T \U \V \W \X \Y \Z \
a \b \c \d \e \f \g \h \i \j \k \l \m \n \o \p \q \r \s \t \u \v \w \x \y \z)  

и решения

user> (time (doall (stackoverflow/letters "ascii"))) 
"Elapsed time: 666.666654 msecs"                                                 
(\A \B \C \D \E \F \G \H \I \J \K \L \M \N \O \P \Q \R \S \T \U \V \W \X \Y \Z \
a \b \c \d \e \f \g \h \i \j \k \l \m \n \o \p \q \r \s \t \u \v \w \x \y \z) 

довольно интересно.


нет, потому что это просто печать букв ASCII, а не полный набор. Конечно, тривиально печатать 26 строчных и прописных букв, используя два для циклов, но факт в том, что есть еще много "букв" за пределами первых 127 кодовых точек. Java "isLetter" FN по характеру будет верен для этих и многих других.


строку.буквы: Конкатенация строк в нижнем и верхнем регистре под. Специфическое значение зависит от локали и будет обновляться когда локаль.функции setlocale() называется.

Я изменил ответ от Майкл Borgwardt. В моей реализации есть два списка строчных и верхних регистров по двум причинам:

  1. строку.буквы строчные, за которыми следуют прописные.

  2. Java


Я уверен, что буквы недоступны в стандартной библиотеке, поэтому вы, вероятно, остались с ручным подходом.


Если вы не помните диапазоны кодовых точек. Путь грубой силы: - P:

user> (require '[clojure.contrib.str-utils2 :as stru2])
nil
user> (set (stru2/replace (apply str (map char (range 0 256))) #"[^A-Za-z]" ""))
#{\A \a \B \b \C \c \D \d \E \e \F \f \G \g \H \h \I \i \J \j \K \k \L \l \M \m \N \n \O \o \P \p \Q \q \R \r \S \s \T \t \U \u \V \v \W \w \X \x \Y \y \Z \z}
user> 

тот же результат, что и в вашем вопросе, будет задан следующим утверждением, которое должно быть создано вручную в отличие от решения Python:

public class Letters {

    public static String asString() {
        StringBuffer buffer = new StringBuffer();
        for (char c = 'a'; c <= 'z'; c++)
            buffer.append(c);
        for (char c = 'A'; c <= 'Z'; c++)
            buffer.append(c);
        return buffer.toString();
    }

    public static void main(String[] args) {
        System.out.println(Letters.asString());
    }

}