【问题标题】:How can I properly return a token within another call?如何在另一个调用中正确返回令牌?
【发布时间】:2017-02-24 02:12:53
【问题描述】:

我很难在字符串中获取正确的标记。我只能取 (false,true,or,and,not,),()) 之类的标记。如果字符串中的标记是“(假”,那么我需要返回“(”和“假”)。这就是我遇到问题的地方。

例如,我想要的输出是:

line: [ not (false or error true) ]
next token: [not]
next token: [(]
next token: [false]
next token: [or]
next token: [true]
next token: [)]

但我的输出是:

line: [ not (false or error true) ]
next token: [not]
next token: [(]
next token: [or]
next token: [true]
next token: [)]

在迭代扫描“or”的下一个标记时,我之前已经返回了“(”并且我的下一个标记是“false”,但我不知道如何返回它。它跳过它并返回“or” .

这是我的方法。

public boolean hasNext() {
    if(!scan.hasNext()){
        return false;
    }
    return true;
}

public String next() {
    while(scan.hasNext()){
        scan.useDelimiter(" ");
        otherToken = scan.next();

    if(otherToken.contains("(") || otherToken.contains(")")){
        if(otherToken.contains("(")){
            nextToken = otherToken.substring(1, otherToken.length());
            return "(";
        }
        if(otherToken.contains(")")){
            nextToken = ")";
            return otherToken.substring(0, otherToken.length()-1);
        }
    }
    if(otherToken.equals("true") || otherToken.equals("false") || 
            otherToken.equals("or") || otherToken.equals("and") || 
            otherToken.equals("not")){
        nextToken = otherToken;
        return nextToken;
    }
    if(otherToken.equals("(") || otherToken.equals(")")){
        nextToken = otherToken;
        return nextToken;
    }
    else{
        continue;
    }
}
return nextToken;
}

【问题讨论】:

  • 你为什么不想要“错误”作为标记?如果它是一个令牌,那么不仅解决方案会很简单,而且您将了解“错误”在您的令牌中的位置——您将如何找到“错误”令牌的来源??
  • 错误不是我的程序的有效令牌,所以我忽略它
  • 那么,你想要的token之间可以有任意的“垃圾”吗?
  • 是的,我只需要我在上面的问题中列出的有效问题

标签: java iterator token


【解决方案1】:

通过对分隔符正则表达式模式稍作调整,您可以让 java Scanner 返回您想要的标记:

    String line =" not (false or error true) ";
    Scanner scan = new Scanner(line);
    scan.useDelimiter(
            "(?<=(?:\\b(?:false|true|or|and|not)\\b)|[()]|^)" // lookbehind
            +".*?" // non-greedy match all
            +"(?=(?:\\b(?:false|true|or|and|not)\\b)|[()]|$)"); // lookahead
    while(scan.hasNext()) {
        System.out.format("next token: [%s]%n", scan.next());
    }

输出:

下一个令牌:[不是]

下一个标记:[(]

下一个令牌:[false]

下一个标记:[或]

下一个令牌:[true]

下一个标记:[)]

但是,仅使用正则表达式来查找标记本身会简单得多:

    String line = "not (false or error true)";
    Pattern p = Pattern.compile("(?:\\b(?:false|true|or|and|not)\\b)|[()]");
    Matcher m = p.matcher(line);
    while(m.find()) {
        System.out.format("next token: [%s]%n", m.group());
    }

【讨论】:

    【解决方案2】:

    您使用空格作为分隔符。这是为您的字符串“not (false or error true)”创建的令牌列表

    1. 不是
    2. (假
    3. 错误
    4. 真)

    第二个标记是“(false”。如果遇到包含“(”的字符串,则以下代码返回“(”:

    if(otherToken.contains("(") || otherToken.contains(")")){ // STRING (false CONTAINS (
        if(otherToken.contains("(")){ // IF STRING CONTAINS ( WHICH (FALSE DOES
            nextToken = otherToken.substring(1, otherToken.length()); // NOT SURE WHERE nextToken IS USED.
            return "(";  // RETURN "("
        }
        if(otherToken.contains(")")){  // EVEN IF TOKEN IS 
            nextToken = ")";
            return otherToken.substring(0, otherToken.length()-1);
        }
    }
    

    【讨论】:

      【解决方案3】:

      别介意标记化,split() 有一个单行解决方案:

      String[] tokens = input.replaceAll("^.*?(?=[()]|\\b(or|not|true|false)\\b)|((?![()]|\\b(or|not|true|false)\\b).)*$", "")
      .split("((?<=[()])|(?<=\\bor\\b)|(?<=\\bnot\\b)|(?<=\\btrue\\b)|(?<=\\bfalse\\b)).*?((?=[()]|\\b(or|not|true|false)\\b|$))");
      

      live demo

      这首先修剪掉任何前导或尾随的垃圾,然后使用环视来匹配目标标记之间的

      虽然有点像 regex train wreck,但这迎合了任意“其他字符”,前提是单词用空格分隔,并且只提取目标标记。例如,它适用于 "xxx not yyy(zzz false aaa or bbb true ccc)ddd" 等输入。

      【讨论】:

      • @PatrickParker 不,只有可变长度的查找会导致问题。但是正则表达式无论如何都不能正常工作。我正在测试它,直到有点工作,当我有它时我会发布一个工作版本(目前它也在拆分空白)
      • 错误不是有效的令牌,所以我忽略它。错误只是字符串中的一个标记,而不是实际的“错误”
      • @Bohemian 抱歉,它仍然无法正常工作。您正在匹配“错误”中的“或”。检查我的答案。
      • @patrick 大声笑我没有注意到。我已经添加了单词边界......并且演示实际上现在可以工作了。
      猜你喜欢
      • 1970-01-01
      • 2015-04-13
      • 2020-06-22
      • 1970-01-01
      • 2018-08-31
      • 2022-11-29
      • 2020-10-09
      • 1970-01-01
      • 2021-06-14
      相关资源
      最近更新 更多