gpt4 book ai didi

java - 如何使用 Java 的 Scanner 类和正则表达式对输入进行标记化?

转载 作者:搜寻专家 更新时间:2023-10-31 08:08:50 25 4
gpt4 key购买 nike

出于我自己的目的,我正在尝试在 Java 中构建一个分词器,我可以在其中定义一个常规语法并让它根据该语法对输入进行分词。 StringTokenizer 类已弃用,我在 Scanner 中发现了几个函数,它们暗示了我想做什么,但还没有成功。有人知道解决这个问题的好方法吗?

最佳答案

“Scanner”这个名字有点误导,因为这个词通常用来表示词法分析器,而 Scanner 并不是这个意思。它只是您在 C、Perl、 中找到的 scanf() 函数的替代品。与 StringTokenizer 和 split() 一样,它被设计为向前扫描,直到找到给定模式的匹配项,并且在途中跳过的任何内容都将作为标记返回。

另一方面,词法分析器必须检查和分类每个字符,即使它只是决定是否可以安全地忽略它们。这意味着,在每次匹配之后,它可能会应用多个模式,直到找到一个与从那一点开始匹配的模式。否则,它可能会找到序列“//”并认为它找到了注释的开头,而实际上它确实在字符串文字中并且它只是没有注意到左引号。

当然,实际上要复杂得多,但我只是在说明为什么像 StringTokenizer、split() 和 Scanner 这样的内置工具不适合这种任务.但是,可以使用 Java 的正则表达式类进行有限形式的词法分析。事实上,添加 Scanner 类使它变得更容易,因为添加了新的 Matcher API 来支持它,即区域和 usePattern() 方法。这是一个构建在 Java 的正则表达式类之上的基本扫描器示例。

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

关于java - 如何使用 Java 的 Scanner 类和正则表达式对输入进行标记化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/244115/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com