【问题标题】:Java regex , matching variables in a math expression [closed]Java regex,匹配数学表达式中的变量[关闭]
【发布时间】:2012-06-27 06:52:30
【问题描述】:

我有一个字符串输入,它代表一个公式,例如:

BMI = ( Weight / ( Height  * Height ) ) * 703

我希望能够将所有合法变量提取到String[]

合法变量的确定规则与 Java 变量命名约定几乎相同,但只允许使用字母数字字符:

  • 任何字母大写或小写,后面都可以跟一个数字
  • 任何单词/文本
  • 后跟数字的任何单词/文本

因此我希望输出如下所示:

BMI
Weight
Height

这是我目前的尝试:

/* helper method , find all variables in expression,
 * Variables are defined a alphabetical characters a to z, or any word , variables cannot have numbers at the beginning
 * using regex pattern "[A-Za-z0-9\\s]"
 */
public static List<String> variablesArray (String expression)
{
    List<String> varList = null; 
    StringBuilder sb = null; 
    if (expression!=null)
    {
        sb = new StringBuilder(); 

        //list that will contain encountered words,numbers, and white space
        varList = new ArrayList<String>();

        Pattern p = Pattern.compile("[A-Za-z0-9\\s]");
        Matcher m = p.matcher(expression);

        //while matches are found 
        while (m.find())
        {
            //add words/variables found in the expression 
            sb.append(m.group());
        }//end while 

        //split the expression based on white space 
        String [] splitExpression = sb.toString().split("\\s");
        for (int i=0; i<splitExpression.length; i++)
        {
            varList.add(splitExpression[i]);
        }
    }
    return varList; 
}

结果与我预想的不一样。我得到了额外的空行,得到了两次“身高”,而且不应该得到一个数字:

BMI


Weight


Height


Height



703

【问题讨论】:

  • 好的,你的问题是什么?
  • 我想要一个正则表达式,给定代表数学公式的字符串,一次提取所有变量
  • 为什么是正则表达式?你使用了错误的工具来完成这项工作。对于数学表达式,您应该查看扫描仪/解析器组合。
  • 我没有使用错误的工具,您不了解我的项目的全部范围,如果您阅读上面的粗体标准,问题就很清楚了!!!

标签: java regex pattern-matching


【解决方案1】:

使用:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Main
{
  public static void main (String[] args) throws java.lang.Exception
  {
     String formula = "BMI = ( Weight / ( Height * Height ) ) * 703";
     String pattern = "(?:^|(?<=[=+\\-*/()]))\\s*([a-z]+)\\s*(?:$|(?=[=+\\-*/()]))";
     Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
     Matcher m = p.matcher(formula);
     while(m.find()) {
       System.out.println(m.group(1));
     }
  }
}

你会得到:

BMI
Weight
Height
Height

所以之后您需要做的只是remove duplicates,这是一项简单的任务。


查看并测试代码here

【讨论】:

  • 当我将你的正则表达式放入 Pattern p = Pattern.compile("(?:^|(?
  • 在 StackOverFlow 上查看,谢谢
  • @AryanNaim - 答案已用 Java 代码更新
  • 您不需要所有这些反斜杠。字符类中的所有字符都失去了它们的特殊含义,除了最初的 ^ 和连字符(当连字符不是第一个或最后一个时)。
  • @Bohemian - 谢谢你的教训,我已经更新了代码,但是正如你所看到的,其中一个 (\\-) 仍然必须被转义,这是有道理的 :)
【解决方案2】:

这个简单的正则表达式应该为你匹配所有的变量:

"[A-Za-z_][A-Za-z0-9_]*"

我冒昧地将_ 包含在名称中,但如果您真的不想要,可以将其删除:

"[A-Za-z][A-Za-z0-9]*"

不可能唯一匹配变量,但您可以将匹配项插入Set 以删除重复条目。

【讨论】:

  • 感谢正则表达式有效,感谢您抽出宝贵时间阅读我的问题,而不是像用户 EJB 那样投票否决
  • @AryanNaim:我建议你不要在评论中抨击其他用户。请编辑它。
  • 为了学习,我会指出这些表达式不会匹配单个字母的变量名。
  • @Gene:我为什么忘了那个案子?感谢您的评论。
【解决方案3】:

我不确定您为什么要创建一个字符串并将其拆分以转换为数组。除了效率低下之外,除非每个 ID 出现后跟空格,否则该方法将不起作用。

这是一个允许在输出中重复的更简单的代码。要消除重复,只需将 ListArrayList 替换为 SetHashSet

public class Test {

    public static List<String> variablesArray(String expression) {
        if (expression != null) {
            ArrayList<String> vars = new ArrayList<String>();
            Pattern p = Pattern.compile("[a-z][a-z0-9]*", Pattern.CASE_INSENSITIVE);
            Matcher m = p.matcher(expression);
            while (m.find()) {
                vars.add(m.group());
            }
            return vars;
        }
        return null;
    }

    public static void main(String[] args) {
        List<String> vars = variablesArray("BMI=(Weight/(Height*Height)) * 70");
        for (String var : vars) {
            System.out.println(var);
        }
    }
}

如果您确实希望将String [] 作为返回值而不是ArrayList&lt;String&gt;,请在返回时进行转换。

return vars.toArray(new String [vars.size()]);

最后,我想知道你想要完成什么。在表达式中包含标识符列表似乎不是很有用。例如,如果您尝试评估表达式,则此 id 列表将不是您所需要的。

【讨论】:

  • 感谢正则表达式有效,感谢您抽出宝贵时间阅读我的问题,而不是像用户 EJB 那样投票否决
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
  • 1970-01-01
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多