使用场景综述:需要校验dwg中的标准号(标号)是否为现行标准,并将正确标号回写到dwg中
使用场景简述理解:需要校验word中的标准号是否为现行标准,并回写
分析:
综上,经过初步分析,本人认为该项目的难点在于如何识别某字段为标准号,及时间复杂度上。
本项目基于cad2021,c#,根据上述分析,预计循环层数不少于8层,也请大佬帮忙降重
预计循环情况:
a、根据上述的DataTable按行匹配数据
b、将标号前缀(keys)作为循环条件,进行循环查找数据
c、在获取到的文本中依次查询标号前缀,看是否含有,含有的话,取固定长度25位
d、根据标号前缀key,再次循环标号排除前缀
e、根据不含有的字段,再次循环排除
f、根据25位长度,从后往前取,取最后一个数字截止
由此,取出标号
综上,10层循环齐活,刚刚取出数据
1.由于为公司项目,已有图签,故只取图签内的数据。涉及到合图、多dwg的情况,一并解决,无难点
2.从图元中取数据,分为dwg表、图块、单行文本,多行文本。其中多行文本取出的数据,较为麻烦,分为两种数据,一种是带格式的数据,一种是不带格式的数据,如下:
若取不带格式的数据,更容易匹配到标号,但是不容易回写数据。正在尝试不带格式数据直接回写,暂测可行
this.dataGridView1.Columns["FLAG"].DataPropertyName = "flag";
this.dataGridView1.Columns["FilePathCurrent"].DataPropertyName = "FilePathCurrent";
this.dataGridView1.Columns["ObjectId"].DataPropertyName = "ObjectId";
this.dataGridView1.Columns["FileNameCurrent"].DataPropertyName = "FileNameCurrent";
this.dataGridView1.Columns["SourceData"].DataPropertyName = "SourceData";
this.dataGridView1.Columns["SourceSpecificationData"].DataPropertyName = "SourceSpecificationData";
this.dataGridView1.Columns["DealSourceSpecificationData"].DataPropertyName = "DealSourceSpecificationData";
this.dataGridView1.Columns["CheckSourceSpecificationData"].DataPropertyName = "CheckSourceSpecificationData";
this.dataGridView1.Columns["location"].DataPropertyName = "location";
this.dataGridView1.Columns["Remark"].DataPropertyName = "Remark";
System.Data.DataTable dtOut = dt.Clone();
string path = null;
try
{
//根据数据行循环
foreach (System.Data.DataRow dr in dt.Rows)
{
if (dr == null)
{
continue;
}
string sourceData = dr["SourceData"].ToString().Replace("\n", "").Replace("\r", "");
int sourceData_Num = sourceData.Length;
if (string.IsNullOrEmpty(sourceData))
{
continue;
}
//根据关键字前缀循环
foreach (var key in keys)
{
string key_Pre = key.Key;
List<string> key_Pre_Excludes = key.Value;
int index = 0;
//根据判断sourceData是否含有key,并排除sourceData中有key,但不为标准号的情况
for (int j = 0; ; j++)
{
int NS_Index = sourceData.IndexOf(key_Pre, index, StringComparison.OrdinalIgnoreCase);
//sourceData不含key_Pre,直接跳出
if (NS_Index < 0)
{
break;
}
//搜索key_Pre过程中,多次循环后NS_Index值未改变,说明含有前缀但不为标号的情况,sourceData.IndexOf搜索的起始位下标+1
if (j > NS_Index)
{
index = NS_Index + 1;
break;
}
int len = lengthMax;
if (sourceData.Length - NS_Index < lengthMax)
{
len = sourceData.Length - NS_Index;
}
string NS_vars = sourceData.Substring(NS_Index, len);
bool flag = false;
//去除对应 排除标号前缀的 标号前缀排除。例如:含GB,不含GBS
foreach (string key_Pre_Exclude in key_Pre_Excludes.CheckNull())
{
if (NS_vars.StartsWith(key_Pre_Exclude, StringComparison.OrdinalIgnoreCase))
{
flag = true;
index = NS_Index + 1;
j = NS_Index - 1;
break;
}
}
if (flag)
{
continue;
}
string NS_var = Regex.Split(NS_vars, @"\P", RegexOptions.IgnoreCase)[0];//去掉换行后的字符串
//根据不要的关键字,取关键字前面的部分
foreach (string key_Exclude in key_Excludes.CheckNull())
{
if (NS_vars.IndexOf(key_Exclude, StringComparison.OrdinalIgnoreCase) > -1)
{
int temp = NS_vars.IndexOf(key_Exclude, StringComparison.OrdinalIgnoreCase);
NS_vars = sourceData.Substring(NS_Index, temp);
NS_var = Regex.Split(NS_vars, @"\P", RegexOptions.IgnoreCase)[0];
}
}
if (NS_var.Length < lengthMin)
{
break;
}
for (int i = NS_var.Length - 1; i > 0; i--)
{
string tempWord = Regex.Replace(NS_var[i].ToString(), @"\d", "");//剔除数字
if (string.IsNullOrEmpty(tempWord) && !string.IsNullOrEmpty(NS_var[i].ToString()))
{
string DealSourceSpecificationData = sourceData.Substring(NS_Index, i + 1);
System.Data.DataRow drOut = dtOut.NewRow();
drOut = dr;
path = Path.GetDirectoryName(drOut["FilePathCurrent"].ToString());
drOut["SourceSpecificationData"] = NS_vars;
drOut["DealSourceSpecificationData"] = Regex.Split(DealSourceSpecificationData, @"\P", RegexOptions.IgnoreCase)[0];//去掉换行后的字符串
dtOut.Rows.Add(drOut.ItemArray);
//sourceData = sourceData.Replace(str, "");//剔除'str1'
index = NS_Index + 1;//剔除'DealSourceSpecificationData'
j = NS_Index - 1;
break;
}
}
}
}
}
}
catch (Exception ex)
{
LogTool.LogTest(ex.StackTrace);
}
private static string[] GetSpecificationPrefix()
{
string SpecificationPrefix = "GB";
try
{
SpecificationPrefix = IniTool.GetValue("cfg.ini", "Specification", "SpecificationPrefix");
}
catch
{ }
return SpecificationPrefix.Split(',');
}
private static string[] GetExcludeSpecificationPrefix()
{
string SpecificationPrefix = "GB2312";
try
{
SpecificationPrefix = IniTool.GetValue("cfg.ini", "Specification", "ExcludeSpecificationPrefix");
}
catch
{ }
return SpecificationPrefix.Split(',');
}
private static string[] GetExclude()
{
string Exclude = "。";
try
{
Exclude = IniTool.GetValue("cfg.ini", "Specification", "Exclude");
}
catch
{ }
return Exclude.Split('a');
}
private static Dictionary<string, List<string>> GetKeys()
{
string[] key_Pres = GetSpecificationPrefix();//获取标号前缀
string[] key_Pre_Excludes = GetExcludeSpecificationPrefix();//获取排除标号前缀
Dictionary<string, List<string>> keys = new Dictionary<string, List<string>>();
foreach (string key_Pre in key_Pres)
{
List<string> key_Pre_Exclude_List = new List<string>();
foreach (string key_Pre_Exclude in key_Pre_Excludes)
{
if (key_Pre_Exclude.IndexOf(key_Pre, StringComparison.OrdinalIgnoreCase) > -1)
{
key_Pre_Exclude_List.Add(key_Pre_Exclude);
}
}
keys.Add(key_Pre, key_Pre_Exclude_List);
}
return keys;
}
从dwg中取数据,暂无优化空间,已经从标号前缀、去除标号前缀的方向上,做出了优化:
1)根据填写的标号前缀、标号排除前缀、排除序列,将数据模拟成Dictionary<string, List<string>>格式
dic的string为标号前缀,对应的list为标号排除前缀,例如dic={AC,【AC220,AC110】}
SpecificationPrefix=AC,AQ
ExcludeSpecificationPrefix=GBS,GB2312,SHX,AC220,gbc
Exclude=.a,a、a。a,a和
已排除各种循环跑死的情况,例如:
GB6222-2005、GB50316-2000
GBS6222-2005、GBS50316-2000
GB2312、AC220、AC84156-2005
GB2312和AC220heAC84156-2005
例如 AC84156-2005为标准化,AC220、AC110不为标准号,GB50316-2000为标准号,GB2312不为标准号,即删除AC,又想到源字符串可能为AC220,AC84156-2005,此时,均去除,标号未取到
并由此,将循环图元的字符串,改为下标循环的方式,发现AC220时,IndexOf起始下标+1
链接为国家标号链接
http://std.samr.gov.cn/gb/gbQuery
查询时,思路为C端将取出的标准号进行拆分,以-为标准拆成两部分,前面为标号,后面为年份,并将标号中的\、空格等均去除,然后根据标号和年份一起去查询数据库的数据,数据库中的标号,也需要去除\、空格等,提高匹配命中率。去除\、空格的原因为:人工填数据,可能会漏\、空格,也可能会多,所以去除;去除年份的原因,即可能是年份写错,也可能是年份写的位数不对,可能是2位,可能是4位。