当前位置: 代码迷 >> C# >> 谋求简历解析思路
  详细解决方案

谋求简历解析思路

热度:85   发布时间:2016-05-05 04:20:31.0
寻求简历解析思路
参考:http://www.cvanalyze.com/demo
可以将不同格式的(word,pdf,txt,html等)简历解析成统一的格式,从简历文本中提取出候选人的结构化字段,包括姓名,性别,年龄,联系方式,毕业院校,工作单位,求职意向...等等。并将简历导入数据库
1.工作经验等关键词,可能不同简历中有不同的说法,内容有可能是文本,也可能是表格。
2.如何对关键词进行提取?算法之类的怎么弄?
该怎么做?
麻烦大神给点思路。

------解决思路----------------------
真没用过
/// <summary>
    /// 根据模板和一个DataTable得到一个解析字符串
    /// </summary>
    /// <param name="template">字符串模板</param>
    /// <param name="dt">一个DataTable</param>
    /// <returns>返回一个解析模板后的字符串</returns>
    public static string Render(string template, DataTable dt)
    {
        if (dt == null 
------解决思路----------------------
 dt.Rows.Count < 1)
        {
            return "";
        }
        StringBuilder sb = new StringBuilder(1000);
        List<string> arr;
        List<string> columns;
        Analyze(template, out arr, out columns);
        int i;
        foreach (DataRow row in dt.Rows)
        {
            i = 0;
            for (; i < columns.Count; i++)
            {
                sb.Append(arr[i]);
                sb.Append(row[columns[i]].ToString());
            }
            if (i < arr.Count)
            {
                sb.Append(arr[i]);
            }

        }
        return sb.ToString();
    }

    /// <summary>
    /// 根据模板和一个DataTable得到一个解析字符串
    /// </summary>
    /// <param name="template">字符串模板</param>
    /// <param name="dt">一个DataTable</param>
    /// <returns>返回一个解析模板后的字符串</returns>
    /// <param name="rowCount">定义个行数,每隔此行数时调用传入的委托</param>
    /// <param name="act">一个处理输出字符串的委托</param>
    /// <returns></returns>
    public static string Render(string template, DataTable dt,int rowCount,Action<StringBuilder> act)
    {
        if (dt == null 
------解决思路----------------------
 dt.Rows.Count < 1)
        {
            return "";
        }
        StringBuilder sb = new StringBuilder(1000);
        List<string> arr;
        List<string> columns;
        Analyze(template, out arr, out columns);
        int i;
        //计算出每隔多少行调用一次act
        rowCount = rowCount > 0 ? rowCount : dt.Rows.Count + 1;
        int rowNum = 0;
        foreach (DataRow row in dt.Rows)
        {
            rowNum++;
            i = 0;
            for (; i < columns.Count; i++)
            {
                sb.Append(arr[i]);
                sb.Append(row[columns[i]].ToString());
            }
            if (i < arr.Count)
            {
                sb.Append(arr[i]);
            }
            if (rowNum % rowCount == 0)
            {
                act(sb);
            }
        }
            
        return sb.ToString();
    }

    /// <summary>
    /// 根据模板和一个泛型实体集合得到一个解析字符串
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="template">字符串模板</param>
    /// <param name="list">实体集合</param>
    /// <returns>返回一个解析模板后的字符串</returns>
    public static string Render<T>(string template, List<T> list)
    {
        if (list == null 
------解决思路----------------------
 list.Count < 1)
        {
            return "";
        }
        StringBuilder sb = new StringBuilder(1000);
        List<string> arr;
        List<string> columns;
        Analyze(template, out arr, out columns);
        int i;
        Type type = typeof(T);
        foreach (T item in list)
        {
            i = 0;
            for (; i < columns.Count; i++)
            {
                sb.Append(arr[i]);
                sb.Append(GetValue(type, item, columns[i]));
            }
            if (i < arr.Count)
            {
                sb.Append(arr[i]);
            }
        }
        return sb.ToString();
    }

    /// <summary>
    /// 对一个字符串模板进行分析
    /// </summary>
    /// <param name="template">字符串模板</param>
    /// <param name="arr">存储除开列名的其他文本的集合</param>
    /// <param name="columns">存储列名的集合</param>
    static void Analyze(string template, out List<string> arr, out List<string> columns)
    {
        arr = new List<string>();
        columns = new List<string>();
        int previousEndIndex = 0;

        //找到{xxx}
        int startIndex = template.IndexOf('{');
        int endIndex = template.IndexOf('}');

        while (startIndex != -1)
        {
            //存储上一个}和现在搜索到的{之间的字符串,如果是第一次搜索到{,那么previousEndIndex=0则存储的是字符串起始到第一个{之间的字符串
            arr.Add(template.Substring(previousEndIndex, startIndex - previousEndIndex));
            //存储列名
            columns.Add(template.Substring(startIndex + 1, endIndex - startIndex - 1));

            startIndex++;
            endIndex++;
            previousEndIndex = endIndex;

            startIndex = template.IndexOf('{', startIndex);
            endIndex = template.IndexOf('}', endIndex);
        }

        //如果模板不是以}结尾,说明后面还有字符串
        if (previousEndIndex < template.Length)
        {
            arr.Add(template.Substring(previousEndIndex));
        }
        //方法执行到此处,arr.Length==columns.Length或者arr.Length==columns.Length+1
    }

    /// <summary>
    /// 根据一个实体类型,实体实例和属性名,获取属性值
    /// </summary>
    /// <param name="type">实体类型</param>
    /// <param name="item">实体实例</param>
    /// <param name="attrName">属性吗</param>
    /// <returns></returns>
    static string GetValue(Type type, object item, string attrName)
    {
        PropertyInfo property = type.GetProperty(attrName, BindingFlags.Public 
------解决思路----------------------
 BindingFlags.IgnoreCase 
------解决思路----------------------
 BindingFlags.Instance);
        object obj = property.GetValue(item, null);
        if (obj != null)
        {
            return obj.ToString();
        }
        return "";
    }
    /// <summary>
    /// 根据模板,使用正则匹配然后替换输出字符串
    /// </summary>
    /// <param name="template"></param>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static string RenderTemplate(string template, DataTable dt)
    {
        StringBuilder sb = new StringBuilder(1000);
        MatchCollection matches = reg.Matches(template);
        string rowStr = template;
        foreach (DataRow row in dt.Rows)
        {
            rowStr = template;
            foreach (Match match in matches)
            {
                rowStr = rowStr.Replace(match.Value, row[match.Groups[1].Value].ToString());
            }
            sb.Append(rowStr);
            sb.Append("\n");
        }
        return sb.ToString();

    }
------解决思路----------------------
做过简历管理软件,支持纯文本和html解析,不过简历解析的思路与算法不过不能说,测试了一下你提供的那个解析器,解析准确率比我的解析器差多了
------解决思路----------------------
简历解析器就是文本解析器,对关键词及其内容进行分拣,由于目标格式变化多样,首先要创建一个通用解析器,通用解析器的解析准确度是衡量解析能力最重要的指标,对于某些不规范或完全不规范的内容,应建立特定解析器进行辅助解析。
这个演示网站的通用解析器完全不行,他们提供的简历范本的解析都是特定解析,也就是根据简历的格式(如:51job、智联招聘等简历格式)写死规则的,一旦格式变化,就失效了。
------解决思路----------------------
将Excel数据表读取到文本文件
private void btn_Select_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Excel文件
------解决思路----------------------
*.xls";//设置打开文件筛选器
            openFileDialog1.Title = "选择Excel文件";//设置打开对话框标题
            openFileDialog1.Multiselect = false;//设置打开对话框中只能单选
            if (openFileDialog1.ShowDialog() == DialogResult.OK)//判断是否选择了文件
            {
                txt_Path.Text = openFileDialog1.FileName;//在文本框中显示Excel文件名
                CBoxBind();//对下拉列表进行数据绑定
            }
        }

        private void btn_Txt_Click(object sender, EventArgs e)
        {
            //连接Excel数据库
            OleDbConnection olecon = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + txt_Path.Text + ";Extended Properties=Excel 8.0");
            olecon.Open();//打开数据库连接
            OleDbDataAdapter oledbda = new OleDbDataAdapter("select * from [" + cbox_SheetName.Text + "$]", olecon);//从工作表中查询数据
            DataSet myds = new DataSet();//实例化数据集对象
            oledbda.Fill(myds);//填充数据集
            StreamWriter SWriter = new StreamWriter(cbox_SheetName.Text + ".txt", false, Encoding.Default);//实例化写入流对象
            string P_str_Content = "";//存储读取的内容
            for (int i = 0; i < myds.Tables[0].Rows.Count; i++)//遍历数据集中表的行数
            {
                for (int j = 0; j < myds.Tables[0].Columns.Count; j++)//遍历数据集中表的列数
                {
                    P_str_Content += myds.Tables[0].Rows[i][j].ToString() + "  ";//记录当前遍历到的内容
                }
                P_str_Content += Environment.NewLine;//字符串换行
            }
            SWriter.Write(P_str_Content);//先文本文件中写入内容
            SWriter.Close();//关闭写入流对象
            SWriter.Dispose();//释放写入流所占用的资源
            MessageBox.Show("已经将" + cbox_SheetName.Text + "工作表中的数据成功写入到了文本文件中", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void CBoxBind()//对下拉列表进行数据绑定
        {
            cbox_SheetName.Items.Clear();//清空下拉列表项
            //连接Excel数据库
            OleDbConnection olecon = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + txt_Path.Text + ";Extended Properties=Excel 8.0");
            olecon.Open();//打开数据库连接
            System.Data.DataTable DTable = olecon.GetSchema("Tables");//实例化表对象
            DataTableReader DTReader = new DataTableReader(DTable);//实例化表读取对象
            while (DTReader.Read())//循环读取
            {
                string P_str_Name = DTReader["Table_Name"].ToString().Replace('$', ' ').Trim();//记录工作表名称
                if (!cbox_SheetName.Items.Contains(P_str_Name))//判断下拉列表中是否已经存在该工作表名称
                    cbox_SheetName.Items.Add(P_str_Name);//将工作表名添加到下拉列表中
            }
            DTable = null;//清空表对象
            DTReader = null;//清空表读取对象
            olecon.Close();//关闭数据库连接
            cbox_SheetName.SelectedIndex = 0;//设置下拉列表默认选项为第一项
        }

------解决思路----------------------
有些人写的简历,人看着都费劲,别说让机器读了
真能读出来,你程序比人智商高.
------解决思路----------------------
模板,规范,规定死了会简单很多
  相关解决方案