Можно использовать предваряющий поиск (?= или ?!).
Например:
C++ (Qt)
QString s = "abc. abc123...abc!!!abc???abc?abc";
QMap<QString, QString> token({{"@cap", "A-Z0-9"}, {"@end", "!?;."}, {" ", ""}});
auto resolve = [&token] (const QString &s) -> QString { QString r(s); for (auto i = token.begin(); i != token.end(); ++i) r.replace(i.key(), i.value()); return r; };
QRegExp rx(resolve("\\S.* (?:\\b[^@cap])? (?:</?li> | [@end]+(?=[^@end]) | $)"));
rx.setMinimal(true);
for (int pos = 0; (pos = rx.indexIn(s, pos)) != -1; pos += rx.matchedLength())
qDebug() << " match" << rx.cap(0);
Здесь реализована простенькая подстановка (для наглядности регэкспа и избежания ошибок при дублировании подстрок) - так удобнее эспериментировать.
Кстати, смысл "(\\b[^А-ЯA-Z0-9])?" непонятен. С квантификатором ? это выражение будет просто игнорироваться. А без него - какой смысл запрещать конечные односимвольные слова в верхнем регистре?... И, если регистр не важен и не ставится целью исключить именно русский и латинский алфавиты, можно просто использовать [^\\w] или вообще \\W (в класс \w включаются произвольные алфавиты, подчерк, цифры и символы-модификаторы unicode классов Mn, Mc, Me).
ЗЫ. Код на C++11.
ЗЫ2. В коде удалена из регэкспа кириллица, у движка форума некорректный парсинг.