【问题标题】:Parse an InputStream for multiple patterns解析多个模式的 InputStream
【发布时间】:2011-08-05 18:25:55
【问题描述】:

我正在为某些模式解析 InputStream 以从中提取值,例如我会有类似的东西

<span class="filename"><a href="http://example.com/foo">foo</a>

我不想使用成熟的 html 解析器,因为我对文档结构不感兴趣,而只对一些定义明确的信息感兴趣。 (只有他们的顺序很重要)
目前我正在使用一种非常简单的方法,每个模式都有一个对象,其中包含开始和结束“标签”的字符 [](在示例中,打开是 &lt;span class="filename"&gt;&lt;a href=",关闭 " 以获取 url)和一个位置标记。对于 InputStream 读取的每个字符,我遍历所有模式并调用 match(char) 函数,该函数在打开模式匹配后返回 true,从那时起,我在 StringBuilder 中收集以下字符,直到现在活动模式匹配( ) 再次。然后,我使用 Pattern 的 ID 和读取的字符串调用一个函数,以进一步处理它。
虽然这在大多数情况下都可以正常工作,但我想在模式中包含正则表达式,所以我也可以匹配类似

<span class="filename" id="234217"><a href="http://example.com/foo">foo</a>

在这一点上,我确信我会重新发明轮子,因为以前肯定会这样做,而且我真的不想一开始就编写自己的正则表达式解析器。但是,我找不到任何可以满足我要求的东西。
不幸的是,Scanner 类只匹配一个模式,而不是模式列表,我可以使用哪些替代方案?它不应该很重并且可以与 Android 一起使用。

【问题讨论】:

  • 我想知道您的输入在 XML 意义上是否格式正确
  • 完全没有,html可能无效

标签: java regex pattern-matching inputstream


【解决方案1】:

Scanner.useDelimiter(Pattern) API 似乎正是您想要的。您必须使用 OR (|) 分隔的模式字符串。

不过,这种模式很快就会变得非常复杂。

【讨论】:

    【解决方案2】:

    您的意思是您希望将任何&lt;span&gt; 元素与给定的class 属性匹配,而不管它可能具有的其他属性?这很容易:

    Scanner sc = new Scanner(new File("test.txt"), "UTF-8");
    Pattern p = Pattern.compile(
        "<span[^>]*class=\"filename\"[^>]*>\\s*<a[^>]*href=\"([^\"]+)\""
    );
    while (sc.findWithinHorizon(p, 0) != null)
    {
      MatchResult m = sc.match();
      System.out.println(m.group(1));
    }
    

    文件“test.txt”包含您问题的文本,输出为:

    http://example.com/foo
    并关闭
    http://example.com/foo

    【讨论】:

    • 不,我还想匹配其他模式,例如 ...(值)或
      Text
      (文本)并区分不同的模式。
    【解决方案3】:

    您认为这一切以前都做过是对的 :) 您所说的是标记化和解析的问题,因此我建议您考虑 JavaCC。

    当你学习理解它的语法时,JavaCC 有一个学习曲线,所以下面是一个帮助你入门的实现。

    语法是standard JavaCC grammar for HTML 的精简版。您可以添加更多产品以匹配其他模式。

    options {
      JDK_VERSION = "1.5";
      static = false;
    }
    
    PARSER_BEGIN(eg1)
    import java.util.*;
    public class eg1 {
      private String currentTag;
      private String currentSpanClass;
      private String currentHref;
    
      public static void main(String args []) throws ParseException {
        System.out.println("Starting parse");
        eg1 parser = new eg1(System.in);
        parser.parse();
        System.out.println("Finishing parse");
      }
    }
    
    PARSER_END(eg1)
    
    SKIP :
    {
        <       ( " " | "\t" | "\n" | "\r" )+   >
    |   <       "<!" ( ~[">"] )* ">"            >
    }
    
    TOKEN :
    {
        <STAGO:     "<"                 >   : TAG
    |   <ETAGO:     "</"                >   : TAG
    |   <PCDATA:    ( ~["<"] )+         >
    }
    
    <TAG> TOKEN [IGNORE_CASE] :
    {
        <A:      "a"              >   : ATTLIST
    |   <SPAN:   "span"           >   : ATTLIST
    |   <DONT_CARE: (["a"-"z"] | ["0"-"9"])+  >   : ATTLIST
    }
    
    <ATTLIST> SKIP :
    {
        <       " " | "\t" | "\n" | "\r"    >
    |   <       "--"                        >   : ATTCOMM
    }
    
    <ATTLIST> TOKEN :
    {
        <TAGC:      ">"             >   : DEFAULT
    |   <A_EQ:      "="             >   : ATTRVAL
    
    |   <#ALPHA:    ["a"-"z","A"-"Z","_","-","."]   >
    |   <#NUM:      ["0"-"9"]                       >
    |   <#ALPHANUM: <ALPHA> | <NUM>                 >
    |   <A_NAME:    <ALPHA> ( <ALPHANUM> )*         >
    
    }
    
    <ATTRVAL> TOKEN :
    {
        <CDATA:     "'"  ( ~["'"] )* "'"
            |       "\"" ( ~["\""] )* "\""
            | ( ~[">", "\"", "'", " ", "\t", "\n", "\r"] )+
                                >   : ATTLIST
    }
    
    <ATTCOMM> SKIP :
    {
        <       ( ~["-"] )+         >
    |   <       "-" ( ~["-"] )+         >
    |   <       "--"                >   : ATTLIST
    }
    
    
    
    void attribute(Map<String,String> attrs) :
    {
        Token n, v = null;
    }
    {
        n=<A_NAME> [ <A_EQ> v=<CDATA> ]
        {
            String attval;
            if (v == null) {
                attval = "#DEFAULT";
            } else {
                attval = v.image;
                if( attval.startsWith("\"") && attval.endsWith("\"") ) {
                  attval = attval.substring(1,attval.length()-1);
                } else if( attval.startsWith("'") && attval.endsWith("'") ) {
                  attval = attval.substring(1,attval.length()-1);
                }
            }
            if( attrs!=null ) attrs.put(n.image.toLowerCase(),attval);
        }
    }
    
    void attList(Map<String,String> attrs) : {}
    {
        ( attribute(attrs) )+
    }
    
    
    void tagAStart() : {
      Map<String,String> attrs = new HashMap<String,String>();
    }
    {
        <STAGO> <A> [ attList(attrs) ] <TAGC>
        {
          currentHref=attrs.get("href");    
          if( currentHref != null && "filename".equals(currentSpanClass) )
          {
            System.out.println("Found URL: "+currentHref);
          }
        }
    }
    
    void tagAEnd() : {}
    {
        <ETAGO> <A> <TAGC>
        {
          currentHref=null;
        }
    }
    
    void tagSpanStart() : {
      Map<String,String> attrs = new HashMap<String,String>();
    }
    {
        <STAGO> <SPAN> [ attList(attrs) ] <TAGC>
        {
          currentSpanClass=attrs.get("class");
        }
    }
    
    void tagSpanEnd() : {}
    {
        <ETAGO> <SPAN> <TAGC>
        {
          currentSpanClass=null;
        }
    }
    
    void tagDontCareStart() : {}
    {
       <STAGO> <DONT_CARE> [ attList(null) ] <TAGC>
    }
    
    void tagDontCareEnd() : {}
    {
       <ETAGO> <DONT_CARE> <TAGC>
    }
    
    void parse() : {}
    {
        (
          LOOKAHEAD(2) tagAStart() |
          LOOKAHEAD(2) tagAEnd() |
          LOOKAHEAD(2) tagSpanStart() |
          LOOKAHEAD(2) tagSpanEnd() |
          LOOKAHEAD(2) tagDontCareStart() |
          LOOKAHEAD(2) tagDontCareEnd() |
          <PCDATA>
        )*
    }
    

    【讨论】:

    • 嗯,这似乎有点过头了,如果我做对了,如果规范发生变化,我还必须重新编译应用程序,而不仅仅是调整配置文件并重新加载它。
    猜你喜欢
    • 2018-10-12
    • 1970-01-01
    • 2018-08-13
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多