Статьи

Использование регулярных выражений для подвешивания отступа абзаца в Java

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

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

Выход должен быть:

1
2
3
4
There has been an increasing effort in recent years to extract relations between
  entities from natural language text. In this dissertation, I will focus on
  various aspects of recognizing biomedical relations between entities reported
  in scientific articles.

Мой метод

Нам нужно регулярное выражение, чтобы разбить абзац на последовательность строк фиксированной длины. Предположим, что ширина текста равна 80, а отступ равен 3, длина первой строки равна 80. Длина всех остатков равна 77.

Основной процесс алгоритма заключается в следующем

  1. Получите первые 80 символов
  2. Для остальных строк замените точки разделения тремя пробелами.

Чтобы найти точки расщепления, мы используем регулярное выражение (.{1,77})\s+ . Это регулярное выражение ищет подстроку, длина которой меньше и равна 77, а последний символ не является пробелом. Найдя его, заменим группу ( $1 ) на $1\n . Поэтому код Java должен выглядеть следующим образом

1
2
3
String regex = "(.{1,77})\\s+";
String replacement = "   $1\n";
text.replaceAll(regex, replacement);

Это регулярное выражение прекрасно работает, за исключением последней строки. Если данный текст не заканчивается пробелом, как \n , последняя строка не будет обработана правильно. Рассмотрим последнюю строку как

1
in scientific articles.

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

1
2
3
...
   in scientific
articles.

Чтобы преодолеть эту проблему, я добавляю фальшивую «\ n» в конце абзаца. После форматирования удаляю потом.

Другая часть кода тривиальна. Здесь я прилагаю свой исходный код. Я использую общие библиотеки Apache для генерации отступов и подтверждения правильности отступа. Для более свежих кодов, вы можете проверить мой Github

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
   * Format a paragraph to that has all lines but the first indented.
   *
   * @param text text to be formatted
   * @param hangIndent hanging indentation. hangIndent >= 0
   * @param width the width of formatted paragraph
   * @param considerSpace true if only split at white spaces.
   * @return
   */
  public static String hangIndent(String text, int hangIndent, int width,
      boolean considerSpace) {
    Validate.isTrue(
        hangIndent >= 0,
        "hangIndent should not be negative: %d",
        hangIndent);
    Validate.isTrue(width >= 0, "text width should not be negative: %d",
        width);
    Validate.isTrue(
        hangIndent < width,
        "hangIndent should not be less than width: "
        + "hangIndent=%d, width=%d",
        hangIndent,
        width);
 
    StringBuilder sb = new StringBuilder(text.substring(0, hangIndent));
    // Needed to handle last line correctly.
    // Will be trimmed at last
    text = text.substring(hangIndent) + "\n";
    // hang indent
    String spaces = org.apache.commons.lang3.StringUtils
        .repeat(' ', hangIndent);
    String replacement = spaces + "$1\n";
    String regex = "(.{1," + (width - hangIndent) + "})";
    if (considerSpace) {
      regex += "\\s+";
    }
    text = text.replaceAll(regex, replacement);
    // remove first spaces and last "\n"
    text = text.substring(hangIndent, text.length() - 1);
    return sb.append(text).toString();
  }

Связанных с работой

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

Я не уверен, какой способ более эффективен, но абсолютно нерегулярный способ легче реализовать и поддерживать. Поэтому я думаю, что основной смысл этого поста — узнать что-то « НОВОЕ ».