Java 从字符串获取值的复杂正则表达式

Java 从字符串获取值的复杂正则表达式,java,regex,Java,Regex,以下是一些输入示例: 1、2、3 “a”、“b”、“c” ‘a’、‘b’、‘c’ 1、“a”、“b” 字符串周围有单引号,数字没有。在字符串中,双单引号“”(即两次)是单引号的转义字符。以下内容也是有效的输入。 '这'是'一串',1,2 “这”是个奇怪的词,1,2 一、二 在玩了很长时间之后,我最终得到了如下结果: ^(\\d*|(?:(?:')([a-zA-Z0-9]*)(?:')))(?:(?:, *)(\\d*|(?:(?:')([a-zA-Z0-9]*)(?:'))))*$ 这完全不

以下是一些输入示例:

1、2、3
“a”、“b”、“c”
‘a’、‘b’、‘c’
1、“a”、“b”

字符串周围有单引号,数字没有。在字符串中,双单引号“”(即两次)是单引号的转义字符。以下内容也是有效的输入。

'这'是'一串',1,2
“这”是个奇怪的词,1,2
一、二

在玩了很长时间之后,我最终得到了如下结果:

^(\\d*|(?:(?:')([a-zA-Z0-9]*)(?:')))(?:(?:, *)(\\d*|(?:(?:')([a-zA-Z0-9]*)(?:'))))*$
这完全不起作用,也不完整:)

使用Java matcher/group的示例如下:
输入:''la''la',1,3
匹配组:

  • 拉拉
  • 一,
  • 二,
请注意,输出字符串周围没有单引号,只有来自输入的转义引号

有雷格克斯大师吗?谢谢

PS:如果我自己弄明白了,我会告诉你的,仍然在尝试你的问题是你有一个输入列表,它保证是你在这里展示的格式,你只需要把它分成单独的项目?因此,您可能根本不需要正则表达式


如果字符串不能包含逗号,只需在逗号上拆分即可获得单个标记。然后,对于不是数字的标记,删除开始/结束引号。然后将“”替换为“”。问题已解决,不需要正则表达式。

您的问题是,您有一个输入列表,它保证采用此处显示的格式,并且您只需要将其拆分为各个项目?因此,您可能根本不需要正则表达式


如果字符串不能包含逗号,只需在逗号上拆分即可获得单个标记。然后,对于不是数字的标记,删除开始/结束引号。然后将“”替换为“”。问题解决了,不需要正则表达式。

您最好将此过程分为两步进行;首先将其拆分为多个字段,然后对每个字段的内容进行后期处理

\s*('(?:''|[^'])*'|\d+)\s*(?:,|$)

应匹配单个字段。然后迭代每个匹配项(交替执行
.find()
.group(1)
)以按顺序获取每个字段。拉出字段值后,可以将双撇号转换为单撇号;只需对
'
->
'

执行一个简单的字符串替换,您最好将其作为一个两步过程来执行;首先将其拆分为多个字段,然后对每个字段的内容进行后期处理

\s*('(?:''|[^'])*'|\d+)\s*(?:,|$)

应匹配单个字段。然后迭代每个匹配项(交替执行
.find()
.group(1)
)以按顺序获取每个字段。拉出字段值后,可以将双撇号转换为单撇号;只需对
'
->
'

执行一个简单的字符串替换,所有示例字符串都满足以下正则表达式:

('(''|[^'])*'|\d+)(\s*,\s*('(''|[^'])*'|\d+))*
意思是:

(               # open group 1
  '             #   match a single quote
  (''|[^'])*    #   match two single quotes OR a single character other than a single quote, zero or more times
  '             #   match a single quote
  |             #   OR
  \d+           #   match one or more digits
)               # close group 1
(               # open group 3
  \s*,\s*       #   match a comma possibly surrounded my white space characters
  (             #   open group 4
    '           #     match a single quote
    (''|[^'])*  #     match two single quotes OR a single character other than a single quote, zero or more times
    '           #     match a single quote
    |           #     OR
    \d+         #     match one or more digits
  )             #   close group 4
)*              # close group 3 and repeat it zero or more times
一个小演示:

import java.util.*;
import java.util.regex.*;

public class Main { 

    public static List<String> tokens(String line) {
        if(!line.matches("('(''|[^'])*'|\\d+)(\\s*,\\s*('(''|[^'])*'|\\d+))*")) {
            return null;
        }
        Matcher m = Pattern.compile("'(''|[^'])*+'|\\d++").matcher(line);
        List<String> tok = new ArrayList<String>();
        while(m.find()) tok.add(m.group());
        return tok;
    }

    public static void main(String[] args) {
        String[] tests = {
                "1, 2, 3",
                "'a', 'b',    'c'",
                "'a','b','c'",
                "1, 'a', 'b'",
                "'this''is''one string', 1, 2",
                "'''this'' is a weird one', 1, 2",
                "'''''''', 1, 2",
                /* and some invalid ones */
                "''', 1, 2",
                "1 2, 3, 4, 'aaa'",
                "'a', 'b', 'c"
        };
        for(String t : tests) {
            System.out.println(t+" --tokens()--> "+tokens(t));
        }
    }
}

但是,您不能简单地使用现有的(并且经过验证的)CSV解析器吗?我想到了。

所有示例字符串都满足以下正则表达式:

('(''|[^'])*'|\d+)(\s*,\s*('(''|[^'])*'|\d+))*
意思是:

(               # open group 1
  '             #   match a single quote
  (''|[^'])*    #   match two single quotes OR a single character other than a single quote, zero or more times
  '             #   match a single quote
  |             #   OR
  \d+           #   match one or more digits
)               # close group 1
(               # open group 3
  \s*,\s*       #   match a comma possibly surrounded my white space characters
  (             #   open group 4
    '           #     match a single quote
    (''|[^'])*  #     match two single quotes OR a single character other than a single quote, zero or more times
    '           #     match a single quote
    |           #     OR
    \d+         #     match one or more digits
  )             #   close group 4
)*              # close group 3 and repeat it zero or more times
一个小演示:

import java.util.*;
import java.util.regex.*;

public class Main { 

    public static List<String> tokens(String line) {
        if(!line.matches("('(''|[^'])*'|\\d+)(\\s*,\\s*('(''|[^'])*'|\\d+))*")) {
            return null;
        }
        Matcher m = Pattern.compile("'(''|[^'])*+'|\\d++").matcher(line);
        List<String> tok = new ArrayList<String>();
        while(m.find()) tok.add(m.group());
        return tok;
    }

    public static void main(String[] args) {
        String[] tests = {
                "1, 2, 3",
                "'a', 'b',    'c'",
                "'a','b','c'",
                "1, 'a', 'b'",
                "'this''is''one string', 1, 2",
                "'''this'' is a weird one', 1, 2",
                "'''''''', 1, 2",
                /* and some invalid ones */
                "''', 1, 2",
                "1 2, 3, 4, 'aaa'",
                "'a', 'b', 'c"
        };
        for(String t : tests) {
            System.out.println(t+" --tokens()--> "+tokens(t));
        }
    }
}

但是,您不能简单地使用现有的(并且经过验证的)CSV解析器吗?我想到了。

将带引号的字符串与RegExp匹配是一个困难的命题。分隔符文本不仅仅是一个单引号,事实上它是一个单引号加上逗号、行首、行尾,这对您很有帮助。这意味着在合法条目中出现背对背单引号的唯一时间将作为字符串转义的一部分

编写一个与此匹配的regexp对于成功案例来说并不难,但是对于失败案例,它可能变得非常具有挑战性

在匹配文本之前对文本进行清理可能符合您的最佳利益。将所有
\
实例替换为文本
\u005c
,然后将所有
'
实例替换为文本
\u0027
(按该顺序)。您在这里提供了一个转义级别,使得字符串没有特殊字符

现在,您可以使用一个简单的模式,例如
(?:(?:^\s*\s*,\s*)(?:'([^']*)'.[^,]*?)*\s*$

下面是该模式的细分(为了清晰起见,我使用术语“set”表示非捕获分组,“group”表示捕获分组):

引用的参数将在捕获组1中,未引用的参数将在捕获组2中。其他一切都将被丢弃

然后循环匹配的条目并反转编码(按顺序将
\u0027
替换为
'
,将
\u005c
替换为
\
),就完成了


这应该是相当容错的,并且正确地解析一些技术上不正确但可恢复的迟钝场景,例如
1,a''b,2
,但在不可恢复的值(例如
1,a'b,2
)上仍然失败,同时在技术上正确(但可能是无意)的条目
1,'ab,2'

将带引号的字符串与RegExp匹配是一个困难的命题。分隔符文本不仅仅是一个单引号,事实上它是一个单引号加上逗号、行首、行尾,这对您很有帮助。这意味着在合法条目中出现背对背单引号的唯一时间将作为字符串转义的一部分

编写一个与此匹配的regexp对于成功案例来说并不难,但是对于失败案例,它可能变得非常具有挑战性

在匹配文本之前对文本进行清理可能符合您的最佳利益。将所有
\
实例替换为文本
\u005c
,然后将所有
'
实例替换为文本
\u0027
(按该顺序)。您在这里提供了一个转义级别,使得字符串没有特殊字符

现在,您可以使用一个简单的模式,例如
(?:(?:^\s*\s*,\s*)(?:'([^']*)'.[^,]*?)*\s*$

下面是该模式的分解(为了清晰起见,我使用术语“set”来表示未捕获的groupin