从txt文件输入Java正则表达式

时间:2017-01-06 09:05:07

标签: java regex parsing text

我有一个包含一些数学表达式的文本文件。 我需要使用正则表达式将文本解析为组件(单词,句子,标点符号,数字和算术符号),计算数学表达式并使用计算出的数字表达式返回原始形式的文本。 我这样做没有正则表达式(没有计算)。现在我正在尝试使用正则表达式。 我不完全明白如何正确地做到这一点。输入文本如下:

  

Pete喜欢数学5 + 3和jesica太罪(3)。

在我需要的输出中:

  

Pete喜欢数学8和jesica也是0,14。

我需要一些关于正则表达式和来自知道如何做到这一点的人的计算的建议。

我的代码:

while (st.hasMoreTokens()) {

        String s = st.nextToken().trim();
        int size = s.length();
        for (int i=0; i<s.length();i++){
        //with regex. not working variant
        Matcher m = LETTER.matcher(s);
        if (m.matches()){
            parts.add(new Word(s.toCharArray()));
        }
        m = PUNCTUATION.matcher(s);
        if (m.matches()){
            parts.add(new Punctuation(s.charAt(0)));
        }
        Sentence buf = new Sentence(parts);
        if (buf.getWords().size() != 0) {
            sentences.add(buf);
            parts = new ArrayList<PartOfSentence>();
        } else
            parts.add(new Punctuation(s.charAt(0)));

带正则表达式的代码(不工作):

if (size < 1)
            continue;
        if (size == 1) {
            switch (s.charAt(0)) {
            case ' ':               
                continue;
            case ',':
            case ';':
            case ':':
            case '\'':
            case '\"':
                parts.add(new Punctuation(s.charAt(0)));
                break;
            case '.':
            case '?':
            case '!':
                parts.add(new Punctuation(s.charAt(0)));
                Sentence buf = new Sentence(parts);
                if (buf.getWords().size() != 0) {
                    sentences.add(buf);
                    parts = new ArrayList<PartOfSentence>();
                } else
                    parts.add(new Punctuation(s.charAt(0)));
                break;
            default:
                parts.add(new Word(s.toCharArray()));
            }

        } else {
            parts.add(new Word(s.toCharArray()));
        }
    }

没有正则表达式(工作):

cd /d %~dp0..
<OTHER_BATCH_COMMANDS>
cmd.exe

3 个答案:

答案 0 :(得分:0)

我认为你可以从寻找&#34;功能&#34;在输入字符串中匹配。然后所有都不匹配,只需返回一个函数。

例如,我希望这个简短的代码能够满足您的需求:

使用Main方法的类。

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

class AdditionPatternFuntion{
    public static boolean render(String s, ArrayList<String> renderedStrings){
        Pattern pattern = Pattern.compile("(\\d\\+\\d)");
        boolean match = pattern.matcher(s).matches();
        if(match){
            StringTokenizer additionTokenier = new StringTokenizer(s, "+", false);
            Integer firstOperand = new Integer(additionTokenier.nextToken());
            Integer secondOperand = new Integer(additionTokenier.nextToken());
            renderedStrings.add(new Integer(firstOperand + secondOperand).toString());
        }
        return match;
    }
}

Class&#34; AdditionPattern&#34;做真正的工作

tripleUser  
tripleUser
tripleUser  False

当我使用此输入时:

  

Pete喜欢数学3 + 3和Jessica也喜欢6 + 3。

我得到了这个输出:

  

皮特喜欢数学6和杰西卡9。

处理&#34; sin()&#34;你可以做同样的功能:创建一个新类,&#34; SinPatternFunction&#34;例如,并做同样的事情。

我认为你甚至应该创建一个抽象类&#34; FunctionPattern&#34;用抽象方法&#34;渲染&#34;你将使用AssitionPatternFunction和SinPatternFunction类实现它。 最后,您将能够创建一个类,让它调用它&#34; PatternFunctionHandler&#34;,它将创建一个PatternFunction列表(一个SinPatternFunction,一个AdditionPatternFunction(依此类推))然后调用render on on每一个并返回结果。

答案 1 :(得分:0)

这不是一个需要解决的小问题,因为即使匹配的数字也会变得非常复杂。

首先,正则表达式"(\\d*(\\.\\d*)?\\d(e\\d+)?)"可以匹配一个数字来计算小数位和指数格式。

其次,您要解决(至少)三种类型的表达式:二元,一元和函数。对于每一个,我们创建一个匹配solve方法的模式。

第三,有许多库可以实施thisthisreduce方法。

下面的实现不处理嵌套表达式,例如sin(5) + cos(3)或表达式中的空格。

private static final String NUM = "(\\d*(\\.\\d*)?\\d(e\\d+)?)";

public String solve(String expr) {
    expr = solve(expr, "(" + NUM + "(!|\\+\\+|--))"); //unary operators
    expr = solve(expr, "(" + NUM + "([+-/*]" + NUM + ")+)"); // binary operators
    expr = solve(expr, "((sin|cos|tan)\\(" + NUM + "\\))"); // functions

    return expr;
}

private String solve(String expr, String pattern) {
    Matcher m = Pattern.compile(pattern).matcher(expr);

    // assume a reduce method :String -> String that solve expressions 
    while(m.find()){
        expr = m.replaceAll(reduce(m.group()));
    }
    return expr;
}

//evaluate expression using exp4j, format to 2 decimal places, 
//remove trailing 0s and dangling decimal point
private String reduce(String expr){
    double res = new ExpressionBuilder(expr).build().evaluate();
    return String.format("%.2f",res).replaceAll("0*$", "").replaceAll("\\.$", ""); 
}

答案 2 :(得分:0)

您指定的要求是使用正则表达式:

  1. 将文本分为组件(单词,...)
  2. 返回评估了内部算术表达式的文本
  3. 你已经开始使用正则表达式的第一步,但还没有完成它 - 完成后,仍然有:

    1. 识别并解析形成算术(子)表达式的组件。
    2. 评估已识别的(子)表达式组件并生成值。对于使用中缀表示法评估(子)表达式,有exists a very helpful answer
    3. 将值替换替换回原始字符串 - 应该很简单。
    4. 对于文本划分为严格定义的组件,以便稍后对子表达式进行unambiguos评估,我编写了一个样本,尝试named capturing groups in Java。此示例仅处理整数,但浮点应该很容易添加。

      某些测试输入的示例输出如下:

      Matching 'Pete like mathematic 5+3 and jesica too sin(3).'
      WORD('Pete'),WS(' '),WORD('like'),WS(' '),WORD('mathematic'),WS(' '),NUM('5'),OP('+'),NUM('3'),WS(' '),WORD('and'),WS(' '),WORD('jesica'),WS(' '),WORD('too'),WS(' '),FUNC('sin'),FOPENP('('),NUM('3'),CLOSEP(')'),DOT('.')
      Matching 'How about solving sin(3 + cos(x)).'
      WORD('How'),WS(' '),WORD('about'),WS(' '),WORD('solving'),WS(' '),FUNC('sin'),FOPENP('('),NUM('3'),WS(' '),OP('+'),WS(' '),FUNC('cos'),FOPENP('('),WORD('x'),CLOSEP(')'),CLOSEP(')'),DOT('.')
      Matching 'Or arcsin(4.2) we do not know about?'
      WORD('Or'),WS(' '),WORD('arcsin'),OPENP('('),NUM('4'),DOT('.'),NUM('2'),CLOSEP(')'),WS(' '),WORD('we'),WS(' '),WORD('do'),WS(' '),WORD('not'),WS(' '),WORD('know'),WS(' '),WORD('about'),PUNCT('?')
      Matching ''sin sin sin' the catholic priest has said...'
      PUNCT('''),WORD('sin'),WS(' '),WORD('sin'),WS(' '),WORD('sin'),PUNCT('''),WS(' '),WORD('the'),WS(' '),WORD('catholic'),WS(' '),WORD('priest'),WS(' '),WORD('has'),WS(' '),WORD('said'),DOT('.'),DOT('.'),DOT('.')
      

      在命名捕获组使用情况时,我发现编译的Pattern或获取的Matcher API不提供对当前组名的访问是不方便的。示例代码如下。

      import java.util.*;
      import java.util.regex.*;
      
      import static java.util.stream.Collectors.joining;
      
      public class Lexer {
          // differentiating _function call opening parentheses_ from expressions one
          static final String S_FOPENP = "(?<fopenp>\\()";
          static final String S_FUNC = "(?<func>(sin|cos|tan))" + S_FOPENP;
          // expression or text opening parentheses
          static final String S_OPENP = "(?<openp>\\()";
          // expression or text closing parentheses
          static final String S_CLOSEP = "(?<closep>\\))";
          // separate dot, should help with introducing floating-point support
          static final String S_DOT = "(?<dot>\\.)";
          // other recognized punctuation
          static final String S_PUNCT = "(?<punct>[,!?;:'\"])";
          // whitespace
          static final String S_WS = "(?<ws>\\s+)";
          // integer number pattern
          static final String S_NUM = "(?<num>\\d+)";
          // treat '* / + -' as mathematical operators. Can be in dashed text.
          static final String S_OP = "(?<op>\\*|/|\\+|-)";
          // word -- refrain from using \w character class that also includes digits
          static final String S_WORD = "(?<word>[a-zA-Z]+)";
      
          // put the predefined components together into single regular expression
          private static final String S_ALL = "(" +
              S_OPENP + "|" + S_CLOSEP + "|" + S_FUNC + "|" + S_DOT + "|" +
              S_PUNCT + "|" + S_WS + "|" + S_NUM + "|" + S_OP + "|" + S_WORD +
          ")";
          static final Pattern ALL = Pattern.compile(S_ALL); // ... & form Pattern
      
          // named capturing groups defined in regular expressions
          static final List<String> GROUPS = Arrays.asList(
              "func", "fopenp",
              "openp", "closep",
              "dot", "punct", "ws",
              "num", "op",
              "word"
          );
          // divide match into components according to capturing groups
          static final List<String> tokenize(Matcher m) {
              List<String> tokens = new LinkedList<>();
              while (m.find()){
                  for (String group : GROUPS) {
                      String grResult = m.group(group);
                      if (grResult != null)
                          tokens.add(group.toUpperCase() + "('" + grResult + "')");
                  }
              }
      
              return tokens;
          }
      
          // some sample inputs to test
          static final List<String> INPUTS = Arrays.asList(
              "Pete like mathematic 5+3 and jesica too sin(3).",
              "How about solving sin(3 + cos(x)).",
              "Or arcsin(4.2) we do not know about?",
              "'sin sin sin' the catholic priest has said..."
          );
      
          // test
          public static void main(String[] args) {
              for (String input: INPUTS) {
                  Matcher m = ALL.matcher(input);
                  System.out.println("Matching '" + input + "'");
                  System.out.println(tokenize(m).stream().collect(joining(",")));
              }
          }
      }