11

Можно ли полагаться на то, что JVM «умным образом» разрешает диапазон "а-я" или "a-z" в регулярном выражении и добавляет в него все символы некоторого алфавита, который начинается на «а» и заканчивается на «я»?

Ответ: нет, диапазон читается буквально, и это можно подтвердить экспериментом.

Символы Ё и ё не попадают в диапазон юникода, в котором лежат все кириллические символы русского языка. То же самое верно для существенной части других алфавитов: буквы в Unicode идут не подряд. Предлагаю отвлечься от особенностей кириллицы и подумать об абстрактном "a-z", где "a" и "z" — первая и последняя буква какого-то алфавита.

Есть ли в Java готовое решение для того, чтобы описать все "родные" буквы в заданной локали?

Ответ: в Java нет, но есть в ответе к этому вопросу

Нашел про поддержку локалей, но не вполне представляю, как это можно применить в регулярном выражении. Логично бы ожидать character class, какой-нибудь \p{locale_Ru_Ru}, но не нахожу.

Навеяно этим ответом к вопросу «Как определить не русский текст?»

Nick Volynkin
  • 34,094
  • Что мешает определить символьный класс [а-яА-яёЁ]? – a_gura Aug 05 '15 at 23:41
  • @a_gura а в общем виде, если я ге знаю целевого языка? – Nick Volynkin Aug 06 '15 at 04:42
  • 2
    В регулярных выражениях нет такой поддержки (скажем, почти нет), можно только использовать символьный класс для каждого. Я написал такие для некоторых языков, основываясь на данных из Википедии. – Wiktor Stribiżew Aug 06 '15 at 06:56
  • 1
    @stribizhev: О, здорово, полезную очень работу проделали. Может, здесь тоже опубликуете? – Nick Volynkin Aug 06 '15 at 07:22
  • @NickVolynkin: Думаю, не стоит, так как вопрос тут несколько иной, и ответ (по-моему, правильный) уже дан. Регулярные выражения просто "тупо" берут данные из таблицы Юникода подряд между заданными границами диапазона и не знают ничего о языках, использующих данные символы. – Wiktor Stribiżew Aug 06 '15 at 07:32
  • Честно говоря с юникодом все довольно просто. Есть псевдокласс \p{Cyrillic}, добавив к нему класс пробелов и пунктуации получим желаемый результат. – ReinRaus Aug 06 '15 at 11:55
  • @ReinRaus: это в Java есть? Я его почему-то не нашел в документации – Nick Volynkin Aug 06 '15 at 13:42
  • Ох. Извините. Всегда думал, что раз Java позиционирует себя как язык поддерживающий Unicode из коробки, то в нем реализован этот функционал PCRE. – ReinRaus Aug 06 '15 at 17:48
  • @ReinRaus: расскажите уж, где есть? в C#? – Nick Volynkin Aug 06 '15 at 17:49
  • В шарпе есть, но он называется IsCyrillic, а так гарантированно в php и естественно в perl. – ReinRaus Aug 06 '15 at 18:37
  • @stribizhev: я все-таки перевел и немного адаптировал ваш ответ, т.к. он вполне отвечает на мой второй вопрос. См. ссылку в вопросе и http://ru.stackoverflow.com/a/440535/181472 – Nick Volynkin Aug 07 '15 at 17:31
  • @NickVolynkin: Мой ответ, честно говоря, неполный, я собирался (и, наверное, так и сделаю как-нибудь на досуге) пополнить список. Так как я специалист явно не по всем языкам даже Европы, некоторых тонкостей, скорее всего, не учёл. – Wiktor Stribiżew Aug 07 '15 at 18:26
  • @stribizhev: пингуйте, как сделаете. Если сам дополню — сообщу тоже. – Nick Volynkin Aug 07 '15 at 18:37
  • @NickVolynkin: кстати, а что если сделать на гитхабе, например, класс со строковыми константами и обновлять его? – Nick Volynkin Aug 07 '15 at 22:29

3 Answers3

13

Готовые выражения для всех символов в заданной локали

Все ответы, где отдельно не указан источник, основаны на Useful ASCII Ranges. Этот ответ основан на ответе stribizhev на EN.SO.

Кроме первых двух, отсортировано по алфавиту.

Русский алфавит (wikipedia)

[а-яА-ЯёЁ] 

Вся латиница плюс акцентированные символы

(?![×÷])[A-Za-zÀ-ÿ]

Белорусский алфавит (wikipedia)

[ёа-зй-шы-яЁА-ЗЙ-ШЫІіЎў] 

Болгарский алфавит (является подмножеством русского) (wikipedia)

[а-ъьюяА-ЪЬЮЯ] 

Греческий и коптский алфавиты вместе: (wikipedia)

[\u0370-\u03FF\u1F00-\u1FFF]

Испанский алфавит

[a-zA-ZáéíñóúüÁÉÍÑÓÚÜ]

Итальянский алфавит

[a-zA-ZàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚ]

Немецкий алфавит

[a-zA-ZäöüßÄÖÜẞ]

Норвежский алфавит (wikipedia)

[a-zA-ZæøåÆØÅ] 

Польский алфавит

[a-pr-uwy-zA-PR-UWY-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]

В польском языке нет заглавных букв Q, V and X. Если нужен польский + латиница:

[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]

Румынский алфавит (wikipedia)

[a-zA-ZĂÂÎȘȚăâîșț] 

Сербский алфавит (кириллица) (wikipedia)

[А-ИК-ШЂЈ-ЋЏа-ик-шђј-ћџ]

Украинский (wikipedia)

Апостроф — тоже буква.

[а-щА-ЩЬьЮюЯяЇїІіЄєҐґ'] 

Французский алфавит

[a-zA-ZàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒ]

Шведский алфавит (wikipedia)

[a-zA-ZäöåÄÖÅ] 
Nick Volynkin
  • 34,094
  • С польским и, думаю, другими языками, основанными на части латинницы, есть такая проблема, что многие заимствованные слова также имеют оригинальное написание. "Такси" по-польски "taxi", хотя в алфавите отсутствуте буква "x". А в украинским, вообще, апостроф может быть буквой (см. комментарий @Vlad к моему ответу). – Wiktor Stribiżew Aug 07 '15 at 18:30
  • Вот пруф, чтобы не оставаться голословным: The alphabet comprises thirty-three letters, representing thirty-eight phonemes (meaningful units of sound), and an additional sign—the apostrophe. – VladD Aug 07 '15 at 18:48
  • А английский, несмотря на формальное отсутствие в алфавите акцентов, вполне себе использует формы café, naïveté и Übermensch. – VladD Aug 07 '15 at 20:30
  • По немецкому, заглавная ß практически не используется, вместо неё пишут двойное S. В реальности upcase("Spaß") должно выдавать "SPASS". – VladD Aug 07 '15 at 20:57
  • @VladD: для английского можно использовать расширенную латиницу, второе выражение. – Nick Volynkin Aug 07 '15 at 22:17
5

Регулярки просто включают диапазон между порядковыми значениями символов.

Полный кириллический диапазон безусловно включает Ёё и многое другое. Так что, чтобы собрать базовую кириллицу, достаточно задать диапазон вида [\x400-\x4ff] (не уверен что точный синтаксис для этого формата в Java).

Nick Volynkin
  • 34,094
Petr Abdulin
  • 2,130
  • у меня речь о диапазоне a-z или а-я. Я знаю, что в него входит в юникоде, но не вполне уверен, что то же самое входит в регулярках. О том и вопрос. Диапазон [\x400-\x4ff], конечно, включает Ёё, но там есть и много лишнего. Об этом второй вопрос — нет ли готового решения. Похоже, что нет. – Nick Volynkin Aug 06 '15 at 07:20
  • @NickVolynkin если у вас речь о a-z как об "алфавите" то думаю в случае англ. языка здесь речь просто об удобном совпадении, остальное ручками, как выше уже написали. Да, я в нём, надеюсь знаете в хорошем смысле :) – Petr Abdulin Aug 06 '15 at 07:32
  • Нуууу. Это не является диапазоном ни для русского, ни для украинского, ни для белорусского, ни для болгарского, ни для какого-то другого определённого языка — чем же это тогда является? – VladD Aug 07 '15 at 16:38
2

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

int c = Character.MIN_VALUE;
int low = -1;
Pattern pat = Pattern.compile( "^[а-яА-Я]$" );
while ( c <= (int) Character.MAX_VALUE ) {
    if ( pat.matcher( String.valueOf( (char) c ) ).matches() ) {
        if ( low == -1 ) low = c;
    } else {
        if ( low > -1 ) {
            System.out.println( Integer.toHexString( low ) + " - " + Integer.toHexString(c-1) );
            low = -1;
        }
    }
    c++;
}

Для данной регулярки это

410 - 44f

Так что решается все очень просто: как и написал @Petr Abdulin

mymedia
  • 8,602
ReinRaus
  • 17,873
  • 3
  • 47
  • 86
  • Я тут узнал про комбинированные символы и нормализацию Юникода, и понял, что для многих языков просто диапазона недостаточно. Нужно убедиться, что реализация регулярок «понимает», что a+ умлаут — это тоже ä. Или вот в польском: o нет, а ó есть. – Nick Volynkin Jan 31 '17 at 17:39
  • Наверное всё это означает, что не нужно пытаться регулярками определять языковую принадлежность текста. )) – Nick Volynkin Jan 31 '17 at 17:40
  • А в чём разница между проверкой регулярными выражениями и написанием кучи условий сравнения нативным кодом ? – ReinRaus Jan 31 '17 at 20:37
  • Я имел в виду не столько метод, сколько путь решения. Т.е. не по четкому набору символов (который можно проверять хоть регулярками, хоть кучей условий), а по какой-то другой эвристике. Может, по словарям искать совпадения. – Nick Volynkin Jan 31 '17 at 20:42
  • 1
    Иначе «Варкалось. Хливкие шорьки пыряли по наве.» распознается как русский текст, что спорно. ) – Nick Volynkin Jan 31 '17 at 20:43
  • Тут нужен искусственный интеллект тогда :) Ну или хотя бы словарь :) – ReinRaus Jan 31 '17 at 21:23