كيف يمكنني tokenize الإدخال باستخدام الماسح الضوئي الطبقة جافا والتعابير العادية؟

StackOverflow https://stackoverflow.com/questions/244115

سؤال

وفقط لأغراض بلدي، وأنا أحاول أن بناء tokenizer في جاوة حيث يمكنني تحديد قواعد اللغة العادية، وأنها tokenize مدخلات بناء على ذلك. تم إهمال الطبقة StringTokenizer، ولقد وجدت بضع وظائف في الماسح الضوئي التي تلمح نحو ما أريد القيام به، ولكن لم الحظ حتى الان. أحد يعرف وسيلة جيدة للذهاب حول هذا الموضوع؟

هل كانت مفيدة؟

المحلول

واسم "الماسح الضوئي" مضلل بعض الشيء، لأن كلمة كثيرا ما يستخدم ليعني محلل لغوي، وهذا ليس ما هو الماسح الضوئي ل. كل ما هو غير بديلا عن وظيفة scanf() تجد في C، بيرل، <م> وآخرون . مثل StringTokenizer وsplit()، انها مصممة لمسح قدما حتى يجدها مباراة لنمط معين، وبكل ما تخطي على على الطريقة التي عاد كعربون.

وقال محلل لغوي، من ناحية أخرى، أن دراسة وتصنيف كل حرف، حتى لو كان فقط لتحديد ما إذا كان يمكن تجاهلها بأمان. وهذا يعني، بعد كل مباراة، فإنه قد يتم تطبيق عدة أنماط حتى يجدها واحد يطابق <م> ابتداء من هذه النقطة . خلاف ذلك، قد تجد تسلسل "//" وأعتقد أنها وجدت بداية تعليق، عندما يكون حقا داخل سلسلة حرفية وفشلت فقط لاحظت علامة اقتباس فتح.

وانها في الواقع أكثر تعقيدا من ذلك، بالطبع، ولكن أنا فقط توضيح لماذا المدمج في الأدوات مثل StringTokenizer، split() والماسح الضوئي ليست مناسبة لهذا النوع من المهام. غير أنه، يمكن استخدام الفئات التعبير العادي جافا لشكل محدود من التحليل المعجمي. في الواقع، إضافة الطبقة الماسح جعلها أسهل بكثير، بسبب API جديدة المنظر الذي تمت إضافته لتقديم الدعم لها، أي المناطق وطريقة usePattern(). وهنا مثال على الماسح الضوئي بدائية مبنية على أعلى الطبقات باستخدام التعابير المنطقية جاوة.

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

public class RETokenizer
{
  static List<Token> tokenize(String source, List<Rule> rules)
  {
    List<Token> tokens = new ArrayList<Token>();
    int pos = 0;
    final int end = source.length();
    Matcher m = Pattern.compile("dummy").matcher(source);
    m.useTransparentBounds(true).useAnchoringBounds(false);
    while (pos < end)
    {
      m.region(pos, end);
      for (Rule r : rules)
      {
        if (m.usePattern(r.pattern).lookingAt())
        {
          tokens.add(new Token(r.name, m.start(), m.end()));
          pos = m.end();
          break;
        }
      }
      pos++;  // bump-along, in case no rule matched
    }
    return tokens;
  }

  static class Rule
  {
    final String name;
    final Pattern pattern;

    Rule(String name, String regex)
    {
      this.name = name;
      pattern = Pattern.compile(regex);
    }
  }

  static class Token
  {
    final String name;
    final int startPos;
    final int endPos;

    Token(String name, int startPos, int endPos)
    {
      this.name = name;
      this.startPos = startPos;
      this.endPos = endPos;
    }

    @Override
    public String toString()
    {
      return String.format("Token [%2d, %2d, %s]", startPos, endPos, name);
    }
  }

  public static void main(String[] args) throws Exception
  {
    List<Rule> rules = new ArrayList<Rule>();
    rules.add(new Rule("WORD", "[A-Za-z]+"));
    rules.add(new Rule("QUOTED", "\"[^\"]*+\""));
    rules.add(new Rule("COMMENT", "//.*"));
    rules.add(new Rule("WHITESPACE", "\\s+"));

    String str = "foo //in \"comment\"\nbar \"no //comment\" end";
    List<Token> result = RETokenizer.tokenize(str, rules);
    for (Token t : result)
    {
      System.out.println(t);
    }
  }
}

وهذا، بالمناسبة، هو الاستخدام الجيد الوحيد لقد وجدت من أي وقت مضى للأسلوب lookingAt(). : D

نصائح أخرى

إذا فهمت سؤالك جيدا ثم هنا طريقتان سبيل المثال إلى tokenize سلسلة. أنت لا تحتاج حتى الطبقة سكانر، إلا إذا كنت تريد ما قبل الصب الرموز، أو تكرار خلالهم أكثر sofistically من استخدام صفيف. إذا كان الصفيف يكفي مجرد استخدام String.split () على النحو المبين أدناه.

يرجى اعطاء مزيد من المتطلبات اللازمة لتمكين إجابات أكثر دقة.

 import java.util.Scanner;


  public class Main {    

    public static void main(String[] args) {

        String textToTokenize = "This is a text that will be tokenized. I will use 1-2 methods.";
        Scanner scanner = new Scanner(textToTokenize);
        scanner.useDelimiter("i.");
        while (scanner.hasNext()){
            System.out.println(scanner.next());
        }

        System.out.println(" **************** ");
        String[] sSplit = textToTokenize.split("i.");

        for (String token: sSplit){
            System.out.println(token);
        }
    }

}

وإذا كان هذا هو لمشروع بسيط (لتعلم كيفية عمل الأشياء)، ثم انتقل مع ما قاله بالينت باتو.

وإذا كان هذا هو لمشروع أكبر، النظر في استخدام مولد الماسح الضوئي مثل JFlex بدلا من ذلك. إلى حد ما أكثر تعقيدا، ولكن بشكل أسرع وأكثر قوة.

scroll top