【问题标题】:Regex Matching Conflict with Overlapping Symbol正则表达式匹配冲突与重叠符号
【发布时间】:2016-09-21 01:10:08
【问题描述】:

我正在尝试匹配所有包含符号 <> 的令牌,但存在一些冲突。特别是,我的标记是<><//>,以及以<!-- 开头并以--> 结尾的评论。

我的正则表达式如下:

String LTHAN = "<"; 
String GTHAN = ">";
String LTHAN_SLASH = "</";
String GTHAN_SLASH = "/>";
String COMMENT = "<!--.*-->";

然后我通过使用通用方法将它们添加到列表中来编译它们:

public void add(String regex, int token) {
    tokenInfos.add(new TokenInfo(Pattern.compile("^(" + regex + ")"), token));
}

这是我的 TokenInfo 类的样子:

private class TokenInfo {
    public final Pattern regex;
    public final int token;

    public TokenInfo(Pattern regex, int token) {
        super();
        this.regex = regex;
        this.token = token;
    }
}

我匹配并显示列表如下:

public void tokenize(String str) {
    String s = new String(str);
    tokens.clear();
    while (!s.equals("")) {
        boolean match = false;

        for (TokenInfo info : tokenInfos) {
            Matcher m = info.regex.matcher(s);
            if (m.find()) {
                match = true;

                String tok = m.group().trim();
                    tokens.add(new Token(info.token, tok));

                s = m.replaceFirst("");
                break;
            }
        }
    }
}

读取和显示:

    try {
        BufferedReader br;
        String curLine;
        String EOF = null;
        Scanner scan = new Scanner(System.in);
        StringBuilder sb = new StringBuilder();

        try {    
            File dir = new File("C:\\Users\\Me\\Documents\\input files\\example.xml");
            br = new BufferedReader(new FileReader(dir));

            while ((curLine = br.readLine()) != EOF) {
                sb.append(curLine);
                // System.out.println(curLine);
            }
            br.close();
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

        tokenizer.tokenize(sb.toString());

        for (Tokenizer.Token tok : tokenizer.getTokens()) {
            System.out.println("" + tok.token + " " + tok.sequence);
        }
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

示例输入:

<!-- Sample input file with incomplete recipe -->
<recipe name="bread" prep_time="5 mins" cook_time="3 hours">
   <title>Basic bread</title>
   <ingredient amount="3" unit="cups">Flour</ingredient>
   <instructions>
     <step>Mix all ingredients together.</step>
   </instructions>
</recipe>

但是,输出的令牌列表将&lt;/(包括后面的任何字符)识别为单独的令牌,这意味着它似乎永远无法识别令牌&lt;//&gt;。 cmets也有同样的问题。这是我的正则表达式的问题吗?为什么它不能识别模式&lt;//&gt;

希望我的问题很清楚。如有必要,很乐意提供更多详细信息/示例。

【问题讨论】:

  • 它们是否按照声明的顺序添加到列表中?
  • 如果您尝试解析 HTML/XML,我建议改用现有库。
  • 您可能想提及TokenInfoPattern 的来源。 (假设 oAuth 和 java.util,但是 ... 可能是错误的)
  • @RamenChef 我试过更改订单,但这似乎并没有改变任何东西。另外,由于这是一个学校项目,我不能使用外部库。我已将我的 TokenInfo 类添加到 OP。
  • @FieryPhoenix 这与minimal reproducible example 相差甚远。请在您实际匹配您的输入与您的令牌列表的位置添加代码。另外,添加一些示例输入

标签: java regex token


【解决方案1】:

问题:

  1. 您的初始正则表达式^(&lt;) 将匹配整个输入。这个正则表达式意味着文本必须以&lt; 开头,整个输入字符串就是这样。所以你必须修复它。
  2. 如果整个标签(没有文本内容 - 如Basic Bread将所有成分混合在一起)被视为一个标记。所以对应的正则表达式应该是单个正则表达式。

解决方案

尝试将正则表达式更改为以下内容:

  1. 对于单个标签 - &lt;[^&gt;]*&gt;
  2. 对于单个结束标签 - &lt;/[^&gt;]*&gt;;
  3. 对于 cmets - (这已经是正确的)

示例程序

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTest {
    private static ArrayList<TokenInfo> tokenInfoList = new ArrayList<>();
    private static ArrayList<String> tokensList = new ArrayList<>();

    public static void add(String regex, int token) {
        tokenInfoList.add(new TokenInfo(Pattern.compile(regex), token));
    }

    static {
        String LTHAN = "<[^>]*>";
        String LTHAN_SLASH = "</[^>]*>";
        String COMMENT = "<!--.*-->";
        add(LTHAN, 1);
        add(LTHAN_SLASH, 3);
        add(COMMENT, 5);
    }

    private static class TokenInfo {
        public final Pattern regex;
        public final int token;

        public TokenInfo(Pattern regex, int token) {
            super();
            this.regex = regex;
            this.token = token;
        }
    }

    public static void tokenize(String str) {
        String s = new String(str);
        while (!s.equals("")) {
            boolean match = false;
            for (TokenInfo info : tokenInfoList) {
                Matcher m = info.regex.matcher(s);
                if (m.find()) {
                    match = true;
                    String tok = m.group().trim();
                    tokensList.add(tok);
                    s = m.replaceFirst("");
                    break;
                }
            }
            // The following is under the assumption that the Text nodes within the document are not considered tokens and replaced
            if (!match) {
                break;
            }
        }
    }

    public static void main(String[] args) {
        try {
            BufferedReader br;
            String curLine;
            String EOF = null;
            StringBuilder sb = new StringBuilder();

            try {
                File dir = new File("recipe.xml");
                br = new BufferedReader(new FileReader(dir));

                while ((curLine = br.readLine()) != EOF) {
                    sb.append(curLine);
                    // System.out.println(curLine);
                }
                br.close();
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }

            tokenize(sb.toString());

            for (String eachToken : tokensList) {
               System.out.println(eachToken);
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

参考文献

http://www.regular-expressions.info/ 是学习正则表达式的绝佳资源。

【讨论】:

  • 我的朋友,谢谢你。与其质疑和评判我的工作,你实际上帮助了我。我非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-16
  • 2017-11-10
  • 2010-09-24
相关资源
最近更新 更多