4

我正在使用 Java 和正则表达式,需要将一些数据拆分为多个实体。在我的输入中,单引号字符 (') 指定实体的结尾,除非它前面有转义字符,即问号 (?)。

我的 RegEx 是(?<!\\?)\\' 并且我正在使用 Scanner 将输入拆分为单独的实体。所以以下情况可以正常工作:

Hello'There  becomes 2 entities: Hello and There
Hello?'There remains 1 entity:   Hello?'There

但是,当我遇到想要转义问号的情况时,它不起作用。所以:

Hello??'There     should become 2 entities:   Hello?? and There
Hello???'There    should become 1 entity:     Hello???'There
Hello????'There   should become 2 entities:   Hello???? and There
Hello?????'There  should become 1 entity:     Hello????'There
Hello?????There   should become 1 entity:     Hello????There
Hello??????There  should become 1 entity:     Hello?????There

因此,规则是如果有偶数个问号,后跟引号,则应将其拆分。如果有奇数个问号,则不应拆分。

有人可以帮助修复我的正则表达式(希望有解释!)以应对多种情况吗?

谢谢,

菲尔

4

3 回答 3

3

试试这个表达式来匹配偶数情况:(?<=[^\?](?>\?\?){0,1000})'

  • (?<=...)'是一种积极的态度,即每个'前面都有表达式 between (?<=and )will match
  • (?>\?\?)是由 2 个连续问号组成的原子组
  • (?>\?\?){0,1000}表示可以有 0 到 1000 个这些组。请注意,您不能编写(?>\?\?)*,因为表达式需要具有最大长度(最大组数)。但是,您应该能够将上限增加很多,具体取决于表达式的其余部分
  • [^\?](?>\?\?)...表示 2 个问号的组必须以某个字符开头,但不能是问号(否则您会匹配奇数情况)
于 2012-09-07T11:58:14.950 回答
2

不要split()用于这个。这似乎是显而易见的解决方案,但匹配实体本身比匹配分隔符要容易得多。大多数支持正则表达式的语言都有内置的方法,比如 Pythonfindall()或 Ruby 的scan(),但在 Java 中,我们仍然坚持编写样板文件。这是一个例子:

Pattern p = Pattern.compile("([^?']|\\?.)+");
String[] inputs = {
    "Hello??'There",
    "Hello???'There",
    "Hello????'There",
    "Hello?????'There",
    "Hello?????There",
    "Hello??????There"
};
for (String s : inputs)
{
  System.out.printf("%n%s :%n", s);
  Matcher m = p.matcher(s);
  while (m.find())
  {
    System.out.printf("  %s%n", m.group());
  }
}

输出:

Hello??'There :
  Hello??
  There

Hello???'There :
  Hello???'There

Hello????'There :
  Hello????
  There

Hello?????'There :
  Hello?????'There

Hello?????There :
  Hello?????There

Hello??????There :
  Hello??????There

Thomas 使用的任意最大长度噱头,除了令人作呕(无意冒犯,Thomas!)之外,是不可靠的,因为它们不断将错误引入处理这些东西的 Pattern.java 代码中。但是不要将此解决方案视为另一种解决方法;Lookbehinds 永远不应该是您的首选,即使在 .NET 这样的风格中,它们可以可靠且不受限制地工作。

于 2012-09-07T17:31:45.853 回答
0

您确定要使用正则表达式吗?如果您的字符串相对较小和/或执行时间不是大问题,您可以使用字符串生成器和循环来计算“?”的数量。例如

    //Your String
    String x = "Hello??'World'Hello?'World";
    StringBuilder sb = new StringBuilder();
    //Holds your splits
    ArrayList<String> parts = new ArrayList<String>();

    int questionmarkcount = 0;
    int _isEven;

    for (char c : x.toCharArray()) {
        if (c == '?') {
            questionmarkcount++;
            sb.append(c);
        } else if (c == '\'') {
            _isEven = questionmarkcount % 2;
            //if there are an even number of '? or none
            if (_isEven == 0 || questionmarkcount == 0) {
                //add the current split, reset the ? count and clear the String builder
                parts.add(sb.toString());
                sb.delete(0, sb.length());
                questionmarkcount = 0;
            } else {
                //append the question mark, no split is needed
                sb.append(c);
                //start counting from the beginning
                questionmarkcount = 0;
            }
        } else {
            sb.append(c);
        }
    }
    parts.add(sb.toString());

在循环结束时,部分 ArrayList 将保存所有拆分。如果' .

于 2012-09-07T12:34:19.633 回答