Получение данных между одинарными и двойными кавычками (особый случай) - PullRequest
2 голосов
/ 11 октября 2019

Я пишу анализатор строк, который я использую для анализа всех строк из текстового файла. Строки могут быть в одинарных или двойных кавычках, довольно просто, не так ли? Ну не совсем. Я написал регулярное выражение для сопоставления строк, как я хочу. но это дает мне ошибку StackOverFlow для больших строк (я знаю, что java не очень хорош с регулярными выражениями для больших строк), это шаблон регулярных выражений (['"])(?:(?!\1|\\).|\\.)*\1

Это хорошо работает для всех строквходные данные, которые мне нужны, но как только появляется большая строка с ошибкой StackOverFlow, я прочитал похожие вопросы, основанные на этом, такие как this , который предлагает использовать StringUtils.substringsBetween, но не удаетсястроки типа '""', "\\\""

Итак, мой вопрос: что мне делать, чтобы решить эту проблему? Я могу предоставить больше контекста, если необходимо, просто прокомментируйте.

Редактировать: После тестирования ответа

Код:

public static void main(String[] args) {

    final String regex = "'([^']*)'|\"(.*)\"";
    final String string = "local b = { [\"\\\\\"] = \"\\\\\\\\\", [\"\\\"\"] = \"\\\\\\\"\", [\"\\b\"] = \"\\\\b\", [\"\\f\"] = \"\\\\f\", [\"\\n\"] = \"\\\\n\", [\"\\r\"] = \"\\\\r\", [\"\\t\"] = \"\\\\t\" }\n" +
            "local c = { [\"\\\\/\"] = \"/\" }";

    final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
    final Matcher matcher = pattern.matcher(string);

    while (matcher.find()) {
        System.out.println("Full match: " + matcher.group(0));
        for (int i = 1; i <= matcher.groupCount(); i++) {
            System.out.println("Group " + i + ": " + matcher.group(i));
        }
    }
}

Вывод:

Full match: "\\"] = "\\\\", ["\""] = "\\\"", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
Group 1: null
Group 2: \\"] = "\\\\", ["\""] = "\\\"", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t
Full match: "\\/"] = "/"
Group 1: null
Group 2: \\/"] = "/

Он неправильно обрабатывает экранированные кавычки.

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Я бы попробовал без захватить тип цитаты / lookahead / backref для повышения производительности. См. этот вопрос для экранированных символов в строках в кавычках . Он содержит хороший ответ , который развернут . Попробуйте как

'[^\\']*(?:\\.[^\\']*)*'|"[^\\"]*(?:\\.[^\\"]*)*"

Как строка Java:

String regex = "'[^\\\\']*(?:\\\\.[^\\\\']*)*'|\"[^\\\\\"]*(?:\\\\.[^\\\\\"]*)*\"";

Левая сторона обрабатывает одинарные кавычки, правые двойные кавычки. Если какой-либо из них перевешивает другой в вашем источнике, поместите это предпочтительно на левой стороне канала.

Посмотрите эту демонстрацию в regex101 (если вам нужно захватить то, что находится внутри кавычек, использовать группы )

1 голос
/ 11 октября 2019

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

Другой вариант - найти другие стратегии или языки для решения вашей проблемы. Например, если бы вы могли классифицировать свои строки на две категории ' или ", обернутые, чтобы найти другие оптимальные решения.

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

'([^']*)'|"(.*)"

, что, вероятно, не сработает для некоторых других вводимых вами данных, и мы не будемНе знаю.

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

Тест

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegularExpression{

    public static void main(String[] args){

        final String regex = "'([^']*)'|\"(.*)\"";
        final String string = "'\"\"'\n"
             + "\"\\\\\\\"\"";

        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
        final Matcher matcher = pattern.matcher(string);

        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            for (int i = 1; i <= matcher.groupCount(); i++) {
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
        }

    }
}

Вывод

Full match: '""'
Group 1: ""
Group 2: null
Full match: "\\\""
Group 1: null
Group 2: \\\"

Если вы хотите упростить / изменить / изучить выражение, это было объяснено в верхней правой панели regex101.com . Если хотите, вы также можете посмотреть в эту ссылку , как она будет сопоставляться с некоторыми примерами входных данных.


RegEx Circuit

jex.im визуализирует регулярные выражения:

enter image description here

...