Как создать регулярное выражение счетчика статей в Java?

Скажем, например, я хочу взять эту фразу:

{{Привет | Что случилось | Привет} {мир | планета} | {До свидания | Позже} {люди | граждане | жители}}

и случайным образом превратите его в одно из следующих:

Hello world
Goodbye people
What's Up word
What's Up planet
Later citizens
etc.

Основная идея состоит в том, что в каждую пару фигурных скобок заключено неограниченное количество вариантов, разделенных знаком «|». Программа должна пройти и случайным образом выбрать один вариант для каждого набора подтяжек. Имейте в виду, что фигурные скобки могут бесконечно вкладываться друг в друга. Я нашел ветку об этом и попытался преобразовать ее в Java, но это не сработало. Вот код Python, который предположительно работал:

import re
from random import randint

def select(m):
    choices = m.group(1).split('|')
    return choices[randint(0, len(choices)-1)]

def spinner(s):
    r = re.compile('{([^{}]*)}')
    while True:
        s, n = r.subn(select, s)
        if n == 0: break
    return s.strip()

Вот моя попытка преобразовать этот код Python в Java.

public String generateSpun(String text){
    String spun = new String(text);
    Pattern reg = Pattern.compile("{([^{}]*)}");
    Matcher matcher = reg.matcher(spun);
    while (matcher.find()){
       spun = matcher.replaceFirst(select(matcher.group()));
    }
    return spun;
}

private String select(String m){
    String[] choices = m.split("|");
    Random random = new Random();
    int index = random.nextInt(choices.length - 1);
    return choices[index];
}

К сожалению, когда я пытаюсь проверить это, позвонив

generateAd("{{Hello|What's Up|Howdy} {world|planet} | {Goodbye|Later} {people|citizens|inhabitants}}");

В основном в моей программе он выдает ошибку в строке в generateSpun, где объявлен Pattern reg, что дает мне PatternSyntaxException.

java.util.regex.PatternSyntaxException: Illegal repetition
{([^{}]*)}

Может ли кто-нибудь попытаться создать метод Java, который будет делать то, что я пытаюсь сделать?


person Dylan    schedule 03.08.2010    source источник


Ответы (4)


Вот некоторые из проблем с вашим текущим кодом:

  • Вам следует повторно использовать скомпилированный Pattern вместо Pattern.compile каждый раз
  • Вам следует повторно использовать свой Random вместо new Random каждый раз
  • Имейте в виду, что String.split основан на регулярных выражениях, поэтому вы должны split("\\|")
  • Имейте в виду, что фигурные скобки в регулярном выражении Java должны быть экранированы, чтобы соответствовать буквально, поэтому Pattern.compile("\\{([^{}]*)\\}");
  • Вы должны запросить group(1), а не group(), который по умолчанию относится к группе 0
  • Вы неправильно используете replaceFirst, найдите _ 12_ вместо этого
  • Random.nextInt(int n) имеет исключительная верхняя граница (как и многие такие методы в Java)
  • Сам алгоритм фактически не обрабатывает произвольно вложенные фигурные скобки должным образом.

Обратите внимание, что экранирование выполняется с помощью предшествующего символа \, и в качестве строкового литерала Java его необходимо удвоить (т.е. "\\" содержит один символ, обратную косую черту).

Вложение

person polygenelubricants    schedule 03.08.2010
comment
О, еще был String spun = new String(text);, что просто глупо (см. stackoverflow.com/questions/3370184/) - person polygenelubricants; 03.08.2010
comment
Спасибо за помощь. Да, мне нужно исправить этот алгоритм. Это странно, потому что это то же регулярное выражение, что и код Python, и код Python работал. - person Dylan; 04.08.2010
comment
@Dylan: разные разновидности регулярного выражения имеют разные спецификации, поэтому вы должны указывать аромат при задании вопроса о регулярном выражении. { и } - это метасимволы повторения в регулярном выражении (например, x{3} соответствует www), но, очевидно, Python позволяет им отображаться без экранирования в зависимости от контекста. Механизм регулярных выражений Java отличается от Python, по крайней мере, в этом аспекте, среди многих других. - person polygenelubricants; 04.08.2010
comment
Мне не удалось придумать алгоритм для вращения текста за один раз, поэтому я просто сделал метод рекурсивным, пока он не превратился в строку без фигурных скобок или | - person Dylan; 05.08.2010
comment
@Dylan: Рекурсия естественна, поскольку вложенные фигурные скобки подразумевают рекурсивную структуру. Регулярное выражение может быть здесь сложным, поскольку оно не может соответствовать сбалансированным скобкам (без некоторых специальных дополнительных функций, например Perl / C #). - person polygenelubricants; 05.08.2010

Чтобы исправить регулярное выражение, добавьте обратную косую черту перед внешними { и }. Это метасимволы в регулярных выражениях Java. Однако я не думаю, что в результате получится рабочая программа. Вы изменяете переменную spun после того, как она была привязана к регулярному выражению, и я не думаю, что возвращенный Matcher будет отражать обновленное значение.

Я также не думаю, что код Python будет работать для вложенных вариантов. Вы действительно пробовали код Python? Вы говорите, что он «предположительно работает», но было бы разумно проверить это, прежде чем тратить много времени на перенос на Java.

person Jim Garrison    schedule 03.08.2010
comment
Да, я протестировал код Python, и он работает так, как должен. - person Dylan; 04.08.2010

Что ж, я только что создал один на PHP и Python, демо здесь http://spin.developerscrib.com, его по адресу очень ранняя стадия, поэтому может не работать должным образом, исходный код находится на github: https://github.com/razzbee/razzy-spinner

person razzbee    schedule 25.04.2016

Используйте это, будет работать ... Я сделал, и отлично работает

Pattern p = Pattern.compile("cat");
 Matcher m = p.matcher("one cat two cats in the yard");
 StringBuffer sb = new StringBuffer();
 while (m.find()) {
     m.appendReplacement(sb, "dog");
 }
 m.appendTail(sb);
 System.out.println(sb.toString());

и тут

private String select(String m){
    String[] choices = m.split("|");
    Random random = new Random();
    int index = random.nextInt(choices.length - 1);
    return choices[index];
}

m.split("|") используйте m.split("\\|")

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

и используйте Pattern.compile("\\{([^{}]*)\\}");

person Monzur    schedule 22.04.2017