Как я получаю набор всех букв в Java/Clojure?

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

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

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

12
задан Jason Baker 5 April 2010 в 12:00
поделиться

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 в большинстве систем, даже в США.

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

13
ответ дан 2 December 2019 в 03:10
поделиться

Если вам нужны просто символы 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)
20
ответ дан 2 December 2019 в 03:10
поделиться

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

5
ответ дан 2 December 2019 в 03:10
поделиться

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

1
ответ дан 2 December 2019 в 03:10
поделиться

Тот же результат, что и в вашем вопросе, будет иметь следующий оператор, который необходимо сгенерировать вручную, в отличие от решения 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());
    }

}
1
ответ дан 2 December 2019 в 03:10
поделиться

Основываясь на императивном Java-решении Майклса, вот идиоматическое (ленивые последовательности) 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 %))))))

Но сравнение производительности между моим первым подходом

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) 

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

6
ответ дан 2 December 2019 в 03:10
поделиться

string.letters: Объединение строчных и прописных строк, описанное ниже. Конкретное значение зависит от локали и будет обновляться при вызове locale.setlocale ().

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

  1. string.letters - это нижний регистр, за которым следуют верхний регистр.

  2. Java Character.isLetter (char) - это больше, чем просто прописные и строчные буквы, поэтому использование Character.isLetter (char) вернет много результатов при использовании некоторых кодировок, например "windows-1252"

Из Api-Doc: Character.isLetter (char) :

Символ считается буквой , если его общий тип категории, предоставленный Character .getType (ch) - это любое из следующих значений:

 * UPPERCASE_LETTER 
 * LOWERCASE_LETTER 
 * TITLECASE_LETTER 
 * MODIFIER_LETTER 
 * OTHER_LETTER 
 

Не все буквы имеют регистр. Многие символы представляют собой буквы, но не являются ни прописными, ни строчными, ни заглавными буквами .

Таким образом, если string.letters должен возвращать только нижний и верхний регистры, символы TITLECASE_LETTER, , MODIFIER_LETTER и OTHER_LETTER следует игнорировать.

public static String allLetters(final Charset charset) {
    final CharsetEncoder encoder = charset.newEncoder();
    final StringBuilder lowerCases = new StringBuilder();
    final StringBuilder upperCases = new StringBuilder();
    for (char c = 0; c < Character.MAX_VALUE; c++) {
    if (encoder.canEncode(c)) {
    if (Character.isUpperCase(c)) {
    upperCases.append(c);
    } else if (Character.isLowerCase(c)) {
    lowerCases.append(c);
    }
    }
    }
    return lowerCases.append(upperCases).toString();
}

Дополнительно: поведение string.letters изменяется при изменении локали. Возможно, это не применимо к моему решению, потому что изменение локали по умолчанию не меняет кодировку по умолчанию. Из apiDoc:

Кодировка по умолчанию определяется во время запуска виртуальной машины и обычно зависит от языкового стандарта и кодировки базовой операционной системы.

Думаю, кодировку по умолчанию нельзя изменить в запущенной JVM.Таким образом, поведение string.letters «изменить язык» невозможно реализовать только с помощью Locale.setDefault (Locale). Но изменение языкового стандарта по умолчанию в любом случае является плохой идеей:

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

3
ответ дан 2 December 2019 в 03:10
поделиться

На случай, если вы не помните диапазоны кодовых точек. Способ грубой силы :-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> 
1
ответ дан 2 December 2019 в 03:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: