Ваши регулярные выражения для тегов, комментариев и разделов CDATA необходимо разделить на две части:
Pattern TAG_START = Pattern.compile("</?[\\w-]+");
Pattern TAG_END = Pattern.compile("/?>");
Pattern COMMENT_START = Pattern.compile("<!--");
Pattern COMMENT_END = Pattern.compile("-->");
Pattern CDATA_START = Pattern.compile("<\\[CDATA\\[");
Pattern CDATA_END = Pattern.compile("\\]\\]>");
Когда вы получаете совпадение с одним из шаблонов *_START
, вы устанавливаете флаг, указывающий, чтоВы находитесь в другом режиме.Например, совпадение на TAG_START
переводит вас в режим TAG, что означает, что вы находитесь внутри тега.Каждый режим поставляется с собственным набором шаблонов, некоторые из которых используются совместно с другими режимами, а некоторые - для конкретного режима.
Например, в режиме по умолчанию вы ищете шаблоны *_START
, перечисленные выше, а также любые другие подходящие шаблоны.В режиме TAG вы ищите пары атрибут / значение и шаблон TAG_END
, которые не имеют смысла вне тега.И вы всегда ищете шаблон TAG_END
first , чтобы убедиться, что вы все еще в теге.(Или какой *_END
шаблон применяется к режиму, в котором вы находитесь.)
Поскольку режимы могут сохраняться за границами линий, это означает, что вы должны либо сохранить какое-то состояние между рисованием одной линии и рисованием следующей (сложно) или сканировать весь документ каждый раз, когда вы рисуете линию (медленно).И какой бы подход вы ни выбрали, производительность во многом зависит от качества регулярных выражений.Например, ваше регулярное выражение:
"(<\\!--[\\w * \\S]*-->)"
... будет первоначально потреблять все, начиная с <!--
до конца документа, только для того, чтобы откатить потенциально очень длинный путь.Кроме того, если есть два или более комментариев, они будут совпадать с начала первого до конца последнего.По обеим этим причинам я написал бы это так:
"<!--[^-]*+(?>-(?!->))*+-->"
Обратите внимание на использование собственнических квантификаторов (*+
) и атомных групп ((?>...)
).Они не нужны с точки зрения правильности, но они делают регулярное выражение намного более эффективным, что будет особенно важно в этом проекте.
Еще одна вещь: если вы собираетесь использовать для этого find()
, вы также должны добавить \G
(привязку конца последнего совпадения) к началу каждого регулярного выражения, как Friedlсделал в это регулярное выражение из своей книги .