Python用于创建集合运算计算器

时间:2015-07-17 02:31:25

标签: python parsing grammar ply python-plyplus

我试图创建一个计算器,不是为了数字,而是为了设置操作。 为了说明这个概念,我们假设你有一个包含两列的文件。

keyword, userid
hello  , john
hello  , alice
world  , alice
world  , john
mars   , john
pluto  , dave

目标是阅读像

这样的表达式
[hello]

并返回拥有该关键字的用户组。例如

[hello]           -> ['john','alice']
[world] - [mars]  -> ['alice'] // the - here is for the difference operation
[world] * [mars]  -> ['john','alice'] // the * here is for the intersection operation
[world] + [pluto] -> ['john','alice','dave'] // the + here is for union operation

我在python中使用plyplus模块生成以下语法来解析此要求。语法如下所示

 Grammar("""
 start: tprog ;
 @tprog: atom | expr u_symbol expr | expr i_symbol expr | expr d_symbol | expr | '\[' tprog '\]';
 expr:   atom | '\[' tprog '\]';
 @atom: '\[' queryterm '\]' ;
 u_symbol: '\+' ;
 i_symbol: '\*' ;
 d_symbol: '\-' ;
 queryterm: '[\w ]+' ;

 WS: '[ \t]+' (%ignore);
 """)

但是,我无法在网络上找到任何好的链接,将解析后的输出带到下一级,我可以逐步评估解析后的输出。我知道我需要将它解析成某种语法树并定义要应用于每个节点的函数。它的孩子递归。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:0)

我是初学者,但我试图解决你的问题,请原谅我,如果我的答案有一些错误。我建议使用熊猫,我认为在这种情况下效果最佳。

首先将数据保存在csv文件中

然后

from pandas import *

下一行是读取文件并将其转换为数据框

x=read_csv('data.csv')
print(x)

结果

 keyword  userid
0  hello      john
1  hello     alice
2  world     alice
3  world      john
4  mars       john
5  pluto      dave

在下一行中,我们将过滤数据框并将其分配给新变量

y= x[x['keyword'].str.contains("hello")]

其中keyword是感兴趣的列,hello是我们要搜索的内容 结果

  keyword  userid
0  hello      john
1  hello     alice

我们只对第二列感兴趣,所以我们将使用索引来获取它,然后将其保存在一个新变量中

z=y.iloc[:,1]
print(z)

结果

0      john
1     alice

现在最后一步是使用

将数据帧转换为列表
my_list = z.tolist()

print(my_list)

结果

[' john', ' alice']

我认为只需操作结果列表即可实现所需的功能

<强> 更新 我试图解决你有“或”的情况 代码就像这样

from pandas import *

x=read_csv('data.csv')
print(x)
y= x[x['keyword'].str.contains("hello|pluto")]
print(y)

z=y.iloc[:,1]
print(z)
my_list = z.tolist()

print(my_list)

结果

[' john', ' alice', ' dave']

UPDATE2: 我找到了“ - ”和“*”案例的解决方案 首先,我们对两个单词使用相同的代码

from pandas import *

x=read_csv('data.csv')
print(x)
y= x[x['keyword'].str.contains("world")]
print(y)

z=y.iloc[:,1]
print(z)
my_list = z.tolist()

print(my_list)
s= x[x['keyword'].str.contains("mars")]
print(s)

g=s.iloc[:,1]
print(g)
my_list2 = g.tolist()

print(my_list2)

然后我们添加一个循环二减去两个列表

for i in my_list:
    if i in my_list2:
        my_list.remove(i)
print(my_list)

结果

[' alice']

对于交叉点,只需更改最后一位

for i in my_list:
    if i not in  my_list2:
        my_list.remove(i)
print(my_list)

结果

[' john']

答案 1 :(得分:0)

好的,所以这是我放在一起的Java实现,只是为了好玩。它基本上将输入标记化,然后使用分流码算法来评估标记。

请注意,我真的不能100%确定它是否能够正确处理复杂的表达式:运算符优先级,运算顺序等等。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Scanner;

@SuppressWarnings("unchecked")
class Setop {

    public static void main(String[] args) {
        (new Setop()).run();
    }

    private HashMap<String, HashSet<String>> sets;

    private void run() {
        // Read file to initialise sets
        Scanner fin;
        try {
            fin = new Scanner(new File("data"));
        } catch (FileNotFoundException ex) {
            System.out.println("Cannot find data file");
            return;
        }
        sets = new HashMap<String, HashSet<String>>();
        fin.nextLine();
        while (fin.hasNextLine()) {
            String[] l = fin.nextLine().split(",");
            if (l.length == 2) {
                String k = "[" + l[0].trim() + "]";
                String v = l[1].trim();
                if (sets.get(k) == null) {
                    sets.put(k, new HashSet<String>());
                }
                sets.get(k).add(v);
            }
        }
        for (Entry<String, HashSet<String>> e : sets.entrySet()) {
            System.out.print(e.getKey() + ": ");
            for (String s : e.getValue())
                System.out.print(s + ", ");
            System.out.println();
        }
        // Main input/evaluation loop
        Scanner in = new Scanner(System.in);
        while (true) {
            System.out.print("> ");
            String sin = in.nextLine();
            if (sin.trim().equals("")) {
                return;
            }
            evaluate(sin);
        }
    }

    private void evaluate(String sin)
    {
        // Tokenize
        ArrayDeque<String> tokens = new ArrayDeque<String>();
        Matcher m = Pattern.compile(" *((\\[[a-z]+\\])|\\+|\\*|\\-|\\(|\\)) *").matcher(sin);
        int i = 0;
        while (m.find()) {
            if (m.start() != i) {
                System.out.println("Cannot tokenise at pos " + i);
                return;
            }
            i = m.end();
            tokens.add(m.group().trim());
        }
        if (i != sin.length()) {
            System.out.println("Cannot tokenise at pos " + i);
            return;
        }
        // Shunting yard algorithm to evaluate
        ArrayDeque<HashSet<String>> output = new ArrayDeque<HashSet<String>>();
        ArrayDeque<String> operators = new ArrayDeque<String>();
        for (String token : tokens) {
            if (Pattern.matches("\\[[a-z]+\\]", token)) {
                HashSet<String> s = sets.get(token);
                if (s == null) {
                    System.out.println("Cannot find set " + token);
                    return;
                }
                output.push((HashSet<String>)s.clone());
            } else if (Pattern.matches("\\+|\\*|\\-", token)
                || token.equals("(")) {
                operators.push(token);
            } else if (token.equals(")")) {
                while (operators.size() > 0
                    && Pattern.matches("\\+|\\*|\\-", operators.peek())) {
                    if (output.size() < 2) {
                        System.out.println("Cannot evaluate, excess operations");
                        return;
                    }
                    output.push(operate(operators.pop(), output.pop(), output.pop()));
                }
                if (operators.size() == 0
                    || !operators.pop().equals("(")) {
                        System.out.println("Cannot evaluate, unmatched parenthesis");
                        return;
                }
            } else {
                System.out.println("Cannot evaluate, unknown token " + token);
                return;
            }
        }
        while (operators.size() > 0) {
            if (operators.peek().equals("(")) {
                System.out.println("Cannot evaluate, unmatched parenthesis");
                return;
            }
            if (output.size() < 2) {
                System.out.println("Cannot evaluate, excess operations");
                return;
            }
            output.push(operate(operators.pop(), output.pop(), output.pop()));
        }
        if (output.size() != 1) {
            System.out.println("Cannot evaluate, excess operands");
            return;
        }
        for (String s : output.pop()) {
            System.out.print(s + ", ");
        }
        System.out.println();
    }

    private HashSet<String> operate(String op, HashSet<String> b, HashSet<String> a) {
        if (op.equals("+")) {
            // Union
            a.addAll(b);
        } else if (op.equals("*")) {
            // Intersection
            a.retainAll(b);
        } else {
            // Difference
            a.removeAll(b);
        }
        return a;
    }

}