【问题标题】:Getting data between single and double quotes (special case)获取单引号和双引号之间的数据(特殊情况)
【发布时间】:2019-10-11 01:34:24
【问题描述】:

我正在编写一个字符串解析器,用于解析文本文件中的所有字符串,字符串可以在单引号或双引号内,很简单吧?不是真的。我写了一个正则表达式来匹配我想要的字符串。但它在大字符串上给了我StackOverFlow 错误(我知道 java 对大字符串上的正则表达式并不是很好),这是正则表达式模式 (['"])(?:(?!\1|\\).|\\.)*\1

这对我需要的所有字符串输入都很有效,但是一旦有一个大字符串就会抛出 StackOverFlow 错误,我已经阅读了基于此的类似问题,例如 this 建议使用 @987654325 @,但在 '""'"\\\"" 等字符串上会失败

所以我的问题是我应该怎么做才能解决这个问题?如果需要,我可以提供更多上下文,请发表评论。

编辑:测试答案后

代码:

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: \\/"] = "/

它没有正确处理转义的引号。

【问题讨论】:

    标签: java regex string pattern-matching


    【解决方案1】:

    我会尝试捕获引用类型/lookahead/backref 以提高性能。请参阅this question 了解引用字符串中的转义字符。它包含一个nice answer,即unrolled。试试看

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

    作为 Java 字符串:

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

    左边处理单引号,右边处理双引号字符串。如果任何一种在您的来源中过度平衡另一种,最好将其放在管道的左侧。

    See this a demo at regex101(如果您需要捕获引号内的内容,use groups

    【讨论】:

    • 谢谢,用当前数据集解决了我的问题 :)
    【解决方案2】:

    对于溢出状态,您可能希望分配所需的任何资源。您可能希望设计小型基准测试并找出完成任务可能需要的实用资源。

    另一种选择是寻找其他策略或语言来解决您的问题。例如,如果您可以将字符串分类为 '" 两类包装以找到其他一些最佳解决方案。

    否则,您可能想尝试设计简单的表达式并避免反向引用,例如:

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

    对于您可能拥有但我们不知道的其他一些输入,这可能会失败。

    或者也许提出您的问题稍微技术性一点,这样一些有经验的用户可能能够提供更好的答案,such as this answer

    测试

    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 的右上角面板中进行说明。如果您愿意,您还可以在this link 中观看它如何与一些示例输入匹配。


    正则表达式电路

    jex.im 可视化正则表达式:

    【讨论】:

    • 嗯,这个正则表达式确实破坏了我的解析器,我会看看哪个字符串不起作用并重新报告,但是:StackOverFlow 消失了,字符串匹配(甚至是大字符串)。跨度>
    • 好的,所以正则表达式的问题在于它将\\" 视为转义引号,但它是转义反斜杠而不是转义引号,我认为这是我输入的唯一问题,其他似乎工作正常。
    • 感谢您的努力 :)
    猜你喜欢
    • 2017-05-20
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 2021-10-20
    相关资源
    最近更新 更多