我要解析一个字符串,例如:string str = "姓名张三性别男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
我有一个关键字的配置文件
example.xml
<?xml version="1.0" encoding="utf-8"?>
<root>
  <configration EName="姓名">
    <Metadata>name</Metadata>
    <Metadata>姓名</Metadata>
    <Metadata>姓?名</Metadata>    
  </configration>
  <configration EName="性别">
    <Metadata>sex</Metadata>
    <Metadata>性别</Metadata>
  </configration>
  <configration EName="出生日期">
    <Metadata>出生日期</Metadata>
  </configration>
  <configration EName="居住地">
    <Metadata>居住地</Metadata>
  </configration>
  <configration EName="工作年限">
    <Metadata>工作年限</Metadata>
  </configration>
  <configration EName="户口">
    <Metadata>户口</Metadata>
  </configration>
  <configration EName="目前年薪">
    <Metadata>目前年薪</Metadata>
  </configration>
  <configration EName="地址">
    <Metadata>地址</Metadata>
  </configration>
</root>
-------------------------------------------------
我要得到的结果为:
张三

1980年11月19日
上海市
一年以上
上海
2万以下人民币
虹口区大连西路500号
--------------------------------------------------
这个字符串是不可知的,关键字也是允许用户配置的,而且这些关键字在字符串里可能存在,也可能不存在,可能存在的形式为:"姓名",也可能为:"name",不管是"姓名"还是"name",他们同属于一个父节点,因此解析出来的结果是要归结在一起的(可能会同时出现,也可能只出现其中一种).就是说如果是解析中文的时候,遇见"姓名"知道后面跟的是名字,英文的话遇见"name"知道后面是名字.还要一种情况就是关键字的位置是不固定的,可能关键字"居住地"在"性别"前面,等等,而且关键字要支持通配,比如说"姓_名",就是要匹配开头是姓最后是名中间只允许出现一个的字符串也是关键字,来解析结果.********************************************************
解决这个问题的朋友,单独开贴送500分.

解决方案 »

  1.   

    这种处理方式不太好。最好是按照一定的格式存储。比如:如果有人姓名为“名XX”的,出来字符串为“姓名名XX”,这样就有多种解释:姓名:名XX 或者 姓名名:XX. 纯属个人意见。
      

  2.   

    当然不是了,如果是按顺序的话,还用这么麻烦吗?按顺序的话直接用substring()就可以取的出来
      

  3.   

    兄弟把字符串格式搞好,主要点在这,不再于怎么解析.
    姓名..性别..生日期..居住地..工作..户口..目前年薪..地址..
    如果所有的串都象这种格式那就好办,如果不是....不好办
    或者string[]传送
      

  4.   

    楼上的哥们真是搞笑了,如果是固定的格式,还用的着想这么多办法吗,就用substring()就可以搞定了啊,而且关键字是需要配置的,你可能没有看明白我上面写的东西.
      

  5.   

    net_lover(【孟子E章】):
    如楼上所说,如果碰到同关键字怎么办?"姓名:张姓名年龄:18";
    我现在写了代码,如果没有重复的关键字没有问题,如果有的话就出现问题了
      

  6.   

    我这样做的目的在于:通用的方法来解析个人简历,不管是HTML格式.还是WORD格式,或者是EXCEL格式.
      

  7.   

    关键字匹配的原因:
    比如说:"个人说明""个人描述"其实可以归结为同样的内容,而不是两个内容.
    中文简历"姓名",英文简历"name",就是一个内容,而不是两个内容.
    如果遇到重复的关键字,我现在没有甚么好的解决方案.只能是采取优先原则,如果已经遇见了"姓名",那么后面遇见了"姓名"将不做为关键字处理.
      

  8.   

    //参考如下代码,不太熟悉C#和XML,应该还有优化的地方using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Xml;namespace WindowsApplication8
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            private void button1_Click(object sender, EventArgs e)
            {
                XmlDocument vXmlDocument = new XmlDocument();
                vXmlDocument.Load("C:\\Temp\\example.xml");
                XmlNodeList vXmlNodeList = vXmlDocument.GetElementsByTagName("configration");
                string str = "姓名张三性别男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
                string vName;
                int i;
                while (str.Length > 0)
                {
                    vName = null;
                    foreach (XmlNode vXmlNode in vXmlNodeList)
                    {
                        foreach (XmlNode Metadata in vXmlNode.ChildNodes)
                        {
                            if (str.IndexOf(Metadata.InnerText) == 0)
                            {
                                vName = Metadata.InnerText;
                                goto loop;
                            }
                        }
                    }            loop: ;
                    if (vName == null) break;
                    str = str.Remove(0, vName.Length);
                    i = str.Length;
                    foreach (XmlNode vXmlNode in vXmlNodeList)
                    {
                        foreach (XmlNode Metadata in vXmlNode.ChildNodes)
                        {
                            int j = str.IndexOf(Metadata.InnerText);
                            if (j >= 0)
                                i = i < j ? i : j; 
                        }
                    }
                    if (i == str.Length)
                    {
                        textBox1.Text += str + "\r\n";
                        break;
                    }
                    else
                    {
                        textBox1.Text += str.Remove(i) + "\r\n";
                        str = str.Remove(0, i);
                    }
                }
            }
        }
    }
      

  9.   

    string str = "name张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";测试结果如下:
    张三

    1980年11月19日
    上海市
    一年以上
    上海
    2万以下人民币
    虹口区大连西路500号
      

  10.   

    zswang(伴水清清)(专家门诊清洁工):
    textBox1.Text += str.Remove(i)////重载方法少了参数
      

  11.   

    伴水,Delphi区的牛人,怎么也开始弄C#这种玩具语言了~
      

  12.   

    to viena
    能在C#中看到Delphi的影子
    回答问题也是种学习的方式
    (主要是Delphi的人气渐渐少了,到这里混点分 :))to 楼主
    我用的是2005调试
    我再看看怎么把Remove换成Substring
      

  13.   

    //修改后....        private void button1_Click(object sender, EventArgs e)
            {
                XmlDocument vXmlDocument = new XmlDocument();
                vXmlDocument.Load("C:\\Temp\\example.xml");
                XmlNodeList vXmlNodeList = vXmlDocument.GetElementsByTagName("configration");
                string str = "name张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
                string vName;
                int i;
                while (str.Length > 0)
                {
                    vName = null;
                    foreach (XmlNode vXmlNode in vXmlNodeList)
                    {
                        foreach (XmlNode Metadata in vXmlNode.ChildNodes)
                        {
                            if (str.IndexOf(Metadata.InnerText) == 0)
                            {
                                vName = Metadata.InnerText;
                                goto loop;
                            }
                        }
                    }            loop: ;
                    if (vName == null) break;
                    str = str.Substring(vName.Length, str.Length - vName.Length);
                    i = str.Length;
                    foreach (XmlNode vXmlNode in vXmlNodeList)
                    {
                        foreach (XmlNode Metadata in vXmlNode.ChildNodes)
                        {
                            int j = str.IndexOf(Metadata.InnerText);
                            if (j >= 0)
                                i = i < j ? i : j;
                        }
                    }
                    if (i == str.Length)
                    {
                        textBox1.Text += str + "\r\n";
                        break;
                    }
                    else
                    {
                        textBox1.Text += str.Substring(0, i) + "\r\n";
                        str = str.Substring(i, str.Length - i);
                    }
                }
      

  14.   

    谢谢zswang(伴水清清)(专家门诊清洁工),我会单独开贴给你结200分.
    你的代码考虑的情况少了,如果说
    string str = "我们都是中国人姓名张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
    这样的话就会出问题了,理想的情况下应该是找出字符串的第一个关键字,然后往下面解析
      

  15.   

    //精简一下,从新贴一个
            private XmlDocument vXmlDocument = new XmlDocument();
            private string str = "我们都是中国人姓名张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
            //private string str = "name张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
                
            private bool SearchName( // 搜索最近一个关键字
                int AStartIndex, // 搜索开始序号
                out int AReturnIndex, // 返回搜索到的位置
                out string AReturnName)
            {
                AReturnIndex = str.Length;
                AReturnName = null;
                XmlNodeList vXmlNodeList = vXmlDocument.GetElementsByTagName("configration");
                foreach (XmlNode vXmlNode in vXmlNodeList)
                {
                    foreach (XmlNode Metadata in vXmlNode.ChildNodes)
                    {
                        int j = str.IndexOf(Metadata.InnerText, AStartIndex);
                        //关于正则表达式,可以修改这里实现
                        if ((j >= 0) && (AReturnIndex > j))
                        {
                            AReturnIndex = j;
                            AReturnName = Metadata.InnerText;
                        }
                    }
                }
                return AReturnName == null;
            }        private void button1_Click(object sender, EventArgs e)
            {
                vXmlDocument.Load("C:\\Temp\\example.xml");
                int vLastIndex = 0;
                int vSearchIndex;
                string vSearchName;            SearchName(0, out vSearchIndex, out vSearchName);
                while (vSearchName != null)
                {
                    //textBox1.Text += vSearchName + "="; // test
                    vLastIndex = vSearchIndex + vSearchName.Length;
                    SearchName(vLastIndex, out vSearchIndex, out vSearchName);
                    textBox1.Text += str.Substring(vLastIndex, vSearchIndex - vLastIndex) + "\r\n";
                }
            }
      

  16.   

    由于顺序可能不是按照xml文件结点的顺序,所以为方便起见,每次匹配时都是对的全部字符串进行的匹配,这样可能会影响效率,但好在简历一般都不会太长..如下,目前由于对通配符的说明还不够明确,所以暂时还没写,如果需要,以后可以想办法补上..初学C#,很多地方还得优化,不过希望能对楼主有所帮助...class Program
        {
            static void Main(string[] args)
            {
                //定义一个列表,用于存储所有关键字
                List<string> list = new List<string>();
                XmlDocument doc = new XmlDocument();
                doc.Load(@"../../test.xml");
                XmlNodeList nodes = doc.SelectNodes(@"//configration");            //定义一个数组用于存储 
                KeyWord[] keyWords = new KeyWord[nodes.Count];
                int i = 0;
                foreach (XmlNode node in nodes)
                {
                    KeyWord key = new KeyWord();
                    string attri = node.Attributes["EName"].Value;
                    key.EName = attri;
                    if (!list.Contains(attri))
                    {
                        list.Add(attri);
                    }
                    foreach (XmlNode childnode in node.ChildNodes)
                    {
                        string text = childnode.InnerText;
                        key.MetaDatas.Add(text);
                        if (!list.Contains(text))
                        {
                            list.Add(text);
                        }
                    }
                    keyWords[i++] = key;
                }            //测试字符串
                string str = "姓名张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";            foreach (KeyWord key in keyWords)
                {
                    //起始点
                    int startIndex = str.IndexOf(key.EName);
                    //终点
                    int endIndex = -1;
                    if (startIndex == -1)
                    {
                        //用子关键字进行搜索
                        foreach (string s in key.MetaDatas)
                        {
                            startIndex = str.IndexOf(s);
                            if (startIndex != -1)
                            {
                                startIndex += s.Length;
                                break;
                            }
                        }
                    }
                    else
                    {
                        startIndex += key.EName.Length;
                    }                //看通过子关键字进行搜索后是否存在
                    if (startIndex != -1)
                    {
                        //查找终点,即找出离此关键字最近的关键字所在的位置
                        foreach (string s in list)
                        {
                            //先将此关键字及其子关键字从列表中排除
                            int index = str.Substring(startIndex).IndexOf(s);
                            if ((endIndex == -1 && index != -1) || (endIndex != -1 && index != -1 && index < endIndex))
                            {
                                //替换endIndex
                                endIndex = index;
                            }
                        }
                        if (endIndex == -1)
                        {
                            key.Value = str.Substring(startIndex);
                        }
                        else
                        {
                            key.Value = str.Substring(startIndex, endIndex);
                        }
                    }
                }            //测试
                foreach (KeyWord key in keyWords)
                {
                    Console.WriteLine(key.EName + ": " + key.Value);
                }
            }
        }
        //定义一个参数类
        public class KeyWord
        {
            public string EName = "";
            public List<string> MetaDatas = new List<string>();
            public string Value = "";
        }
      

  17.   

    string str = "姓名张三sex男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";输出如下:
    姓名: 张三
    性别: 男
    出生日期: 1980年11月19日
    居住地: 上海市
    工作年限: 一年以上
    户口: 上海
    目前年薪: 2万以下人民币
    地址: 虹口区大连西路500号string str = "sex男出生日期1980年11月19日姓名张三居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";输出如下:
    姓名: 张三
    性别: 男
    出生日期: 1980年11月19日
    居住地: 上海市
    工作年限: 一年以上
    户口: 上海
    目前年薪: 2万以下人民币
    地址: 虹口区大连西路500号.....
      

  18.   

    楼主描述不清楚。
    楼主给的是  <configration EName="姓名">
        <Metadata>name</Metadata>
        <Metadata>姓名</Metadata>
        <Metadata>姓?名</Metadata>    
      </configration>EName应该就是字段名字,不知道EName要做什么。就是说EName可以是name,姓名,姓?名也作为字段名字?????????根据这个名字找对应的数据就可以了。============
    我要得到的结果为:?
    张三

    1980年11月19日
    上海市
    一年以上
    上海
    2万以下人民币
    虹口区大连西路500号不知道你的这些数据哪来的?什么格式?你的问题里并没有说明。既然是xml 格式,用xml的类就可以了
      

  19.   

    发布自己写的,能实现功能,没有进行代码优化.
    private int returnIndex(string indexValue)
    {
    string ss = indexValue.Substring(0,indexValue.IndexOf("."));
    int _index = Convert.ToInt32(ss);
    return _index;
    } private int returnLength(string indexValue)
    {
    string ss = indexValue.Substring(indexValue.IndexOf("."),indexValue.Length-indexValue.IndexOf("."));
    string cc = ss.Substring(1,ss.LastIndexOf(".")-1);
    int _length = Convert.ToInt32(cc);
    return _length; } private string returnValue(string indexValue)
    {
    int i = indexValue.LastIndexOf(".");
    string ss = indexValue.Substring(i).Replace(".","");
    return ss;
    }
    private void button2_Click(object sender, System.EventArgs e)
    {
    string str = "姓名:  中国人 居住地: 上海市性别:  男 出生日期: 1983年03月19日";
    str = str.Replace(":","").Replace(" ","");
    ArrayList al = new ArrayList(); 
    sl = new SortedList();
    al.Add("姓名");
    al.Add("性别");
    al.Add("出生日期");
    al.Add("居住地");
    for(int i=0;i<al.Count;i++)
    {
    Regex r = new Regex(al[i].ToString());
    Match m = r.Match(str);
    if(m.Success)
    {
    sl.Add(m.Index,m.Index+"."+m.Length+"."+m.Value);
    } }
    sList = sl.GetValueList();
    for(int j=0;j<sl.Count;j++)
    {
    int index = returnIndex(sList[j].ToString());
    int length = returnLength(sList[j].ToString());
    if((j+1)<sl.Count)
    {
    this.richTextBox1.Text +=  returnValue(sList[j].ToString())+":"+str.Substring(index+length,returnIndex(trueValue(j+1))-(index+length))+"\n";
    }
    else
    {
    int v = returnIndex(trueValue(j+1))+returnLength(trueValue(j+1));
    int f = str.Length;
    this.richTextBox1.Text +=  returnValue(sList[j].ToString())+":"+str.Substring(v,str.Length-v)+"\n";
    }
    }
    } private string trueValue(int k)
    {
    string newString = "";
    if(k>=sl.Count)
    {
    for(int i=0;i<sl.Count;i++)
    {
    if(k == i+1)
    {
    newString = sList[i].ToString();
    }
    }
    }
    else
    {
    for(int m=0;m<sl.Count;m++)
    {
    if(k == m)
    {
    newString = sList[m].ToString();
    }
    }
    }
    return newString ;
    }
      

  20.   

    下一步采用System.Text.RegularExpressions.MatchCollection来获取匹配出来的关键字的集合,然后对关键字集合进行分析,然后给XML设置分析优先级,这样可以缓解出现重复的关键字.
      

  21.   

    string str = "姓名张三性别男出生日期1980年11月19日居住地上海市工作年限一年以上户口上海目前年薪2万以下人民币地址虹口区大连西路500号";
    //添几个关键字
    ArrayList al=new ArrayList();
    al.Add("姓名");al.Add("性别");al.Add("出生日期");al.Add("居住地");
    al.Add("工作年限");al.Add("户口");al.Add("目前年薪");al.Add("地址");
    ArrayList alIndex=new ArrayList();
    Hashtable hs=new Hashtable();
    for(int i=0;i<al.Count;i++)
    {
    string strKey=(string)al[i];
    int iKeyIndex=str.IndexOf(strKey);
    if(iKeyIndex>=0)
    {
    iKeyIndex+=strKey.Length;
    if(!alIndex.Contains(iKeyIndex))
    {
    alIndex.Add(iKeyIndex);
    hs.Add(iKeyIndex,strKey);
    }
    }
    }
    alIndex.Sort(null);
    int[] iIndexs=(int[])alIndex.ToArray(typeof(int));
    ArrayList alResult=new ArrayList();
    for(int i=0;i<iIndexs.Length;i++)
    {
    if(i==iIndexs.Length-1)
    alResult.Add(str.Substring(iIndexs[i]));
    else
    alResult.Add(str.Substring(iIndexs[i],iIndexs[i+1]-iIndexs[i]-hs[iIndexs[i+1]].ToString().Length));
    }
    //alResult
    //有史以来,个人最变态写法之一
      

  22.   

    用正则表达式去匹配咯。另一种思路是,你先找个分词引擎帮你分词,或者你从HTML/Word/Excel格式中获取字符串时先粗略分段。例如在<table />中,"<td>姓名</td><td>张三</td>",这显然是已经帮你分段吧,你不分段就合并起来,然后又要研发自己的智能系统去分段,就多此一举了。