C#字符串处理:视觉检测结果格式化输出的必修课

📅 2026/7/22 3:48:42
C#字符串处理:视觉检测结果格式化输出的必修课
前言上一篇我们讲了数组知道了图像本质上就是一个二维数组。那检测完之后呢你得把结果告诉别人——不管是显示在界面上、保存到文件里还是发给PLC。这时候字符串处理就是你绕不开的必修课了。一字符串是什么大白话讲字符串就是一串字符的序列用双引号包起来。stringmsg检测完成;stringresultOK;stringcode1234567890;在机器视觉里字符串的用处太多了OCR识别出来的字符 → 就是一个字符串条码/二维码解码结果 → 字符串检测结果OK/NG、尺寸数值→ 格式化成字符串输出保存日志、生成报表 → 全是字符串操作重要概念字符串是不可变的这是C#字符串最重要的特性也是新手最容易忽略的。stringsHello;ss World;// 看起来是改了s实际上创建了一个新字符串每次对字符串的“修改”其实都是在内存里创建了一个新的字符串对象旧的等着被垃圾回收。这意味着什么意味着如果你在循环里频繁拼接字符串性能会急剧下降。后面我们会讲怎么解决。二字符串的常用方法1. 判断包含关系Contains、StartsWith、EndsWith视觉检测里经常要判断结果里有没有某个关键词。stringresultProduct OK - Size: 12.5mm;// 判断是否包含OKif(result.Contains(OK)){Console.WriteLine(产品合格);}// 判断是否以Product开头if(result.StartsWith(Product)){Console.WriteLine(这是产品检测结果);}// 判断是否以mm结尾if(result.EndsWith(mm)){Console.WriteLine(单位是毫米);}场景举例**OCR识别出字符后你要判断是不是包含了PASS或者FAILstringocrResultGetOCRResult();// 假设从图像里识别出了文字if(ocrResult.Contains(PASS)){// 通过}elseif(ocrResult.Contains(FAIL)){// 不通过}2. 获取长度Length跟数组一样字符串也有Length属性。stringcodeABC123;intlencode.Length;// len 6场景举例条码识别后检查长度是否符合预期比如二维码通常有固定的字符长度。stringbarcode8901234567890;if(barcode.Length13){Console.WriteLine(EAN-13条码长度正确);}3. 截取子串Substring从字符串里取出一部分。在这里插入代码片stringfullSN:20240721-001;// 从第3个字符开始取索引从0开始stringsnfull.Substring(3);// 20240721-001// 从第3个字符开始取8个stringdatefull.Substring(3,8);// 20240721**场景举例**产品序列号包含日期信息你需要单独提取出来。stringproductCode20240721A001;stringyearproductCode.Substring(0,4);// 2024stringmonthproductCode.Substring(4,2);// 07stringdayproductCode.Substring(6,2);// 214. 分割Split按指定字符把字符串拆成数组。stringdata12.5,8.3,15.6,9.2;string[]valuesdata.Split(,);// values [12.5, 8.3, 15.6, 9.2]**场景举例**一次测量多个尺寸结果用逗号分隔存成字符串读出来的时候用Split拆开。stringmeasureResult12.5,8.3,15.6,9.2;string[]resultsmeasureResult.Split(,);for(inti0;iresults.Length;i){doublevaldouble.Parse(results[i]);Console.WriteLine($第{i1}个尺寸{val}mm);}5. 替换Replace把字符串里的某部分替换成别的。stringmsg检测结果Fail;stringnewMsgmsg.Replace(Fail,NG);// newMsg 检测结果NG**场景举例**不同设备对OK/NG的表示不一样做兼容处理stringresultGetDetectionResult();// 可能是Pass或Failresultresult.Replace(Pass,OK).Replace(Fail,NG);6. 去空格Trim去掉字符串前后的空格。stringraw ABC123 ;stringcleanedraw.Trim();// ABC123**场景举例**OCR识别结果经常带多余空格先Trim一下再处理。三字符串格式化把数据变成好看的文本这是视觉开发里最常用的操作之一——把检测结果整理成人类能看懂的样子。方式一$ 字符串插值推荐C# 6.0 引入的写法最直观、最好用。stringproductName螺丝;doublesize12.5;boolisOKtrue;stringresult$产品{productName}尺寸{size}mm结果{(isOK?OK:NG)};// 产品螺丝尺寸12.5mm结果OK方式二string.Format占位符传统写法用 {0}、{1} 做占位符。stringresultstring.Format(产品{0}尺寸{1}mm结果{2},productName,size,isOK?OK:NG);两种方式效果一样但 $ 插值更简洁推荐使用。数字格式化控制小数点位数视觉检测里经常要控制测量结果的精度。doublevalue12.3456789;// 保留2位小数strings1${value:F2};// 12.35// 保留3位小数strings2${value:F3};// 12.346// 科学计数法strings3${value:E2};// 1.23E001**场景举例**测量结果报表。double[]sizes{12.3456,8.2931,15.6789};bool[]results{true,false,true};for(inti0;isizes.Length;i){stringstatusresults[i]?OK:NG;Console.WriteLine($尺寸{i1}{sizes[i]:F3}mm →{status});}// 输出// 尺寸112.346mm → OK// 尺寸28.293mm → NG// 尺寸315.679mm → OK四字符串拼接的性能问题前面说了字符串是不可变的。如果你在循环里用 拼接字符串每次都会创建新对象。// ❌ 不要这样写性能极差stringlog;for(inti0;i10000;i){loglog检测第i个产品OK\n;}正确的做法是用 StringBuilder// ✅ 推荐这样写StringBuildersbnewStringBuilder();for(inti0;i10000;i){sb.AppendLine($检测第{i}个产品OK);}stringlogsb.ToString();什么时候用 StringBuilder在循环里拼接字符串 → 必须用拼接次数很多几十次以上→ 建议用只是拼接几次 → 直接用 或 $ 就行五字符串在机器视觉里的应用场景场景1检测结果格式化输出// 一次检测的数据DateTimenowDateTime.Now;stringproductIDP001;doublewidth25.678;doubleheight18.234;boolqualitytrue;// 格式化成一行结果stringrecord${now:yyyy-MM-dd HH:mm:ss},{productID},{width:F3},{height:F3},{(quality?OK:NG)};// 2024-07-21 14:30:25,P001,25.678,18.234,OK场景2保存到CSV文件CSV逗号分隔值是视觉项目里最常用的数据存储格式之一。// 多条检测结果拼成一个CSVStringBuildercsvnewStringBuilder();csv.AppendLine(时间,产品ID,宽度,高度,结果);for(inti0;i100;i){stringline${DateTime.Now:HH:mm:ss},P{i:D3},{25.0i*0.1:F3},{18.0i*0.05:F3},OK;csv.AppendLine(line);}// 保存到文件File.WriteAllText(检测结果.csv,csv.ToString());场景3日志记录voidLog(stringmessage){stringlogEntry$[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]{message};// 写入日志文件或显示在界面上Console.WriteLine(logEntry);}// 使用Log(相机初始化成功);Log($检测到产品{productID}尺寸{size:F2}mm);场景4与PLC通信工业现场经常要和PLC通过字符串协议通信。// 组装发送给PLC的指令stringproductIDA001;boolresulttrue;stringcmd$RESULT,{productID},{(result?1:0)};// RESULT,A001,1// 解析PLC发来的数据stringreceivedSTART,A001;string[]partsreceived.Split(,);stringcommandparts[0];// STARTstringparamparts[1];// A001场景5OCR识别结果处理// 假设OCR识别出了一串字符stringocrText ABC-12345 ;// 清理ocrTextocrText.Trim();// ABC-12345// 验证格式是否包含-if(ocrText.Contains(-)){string[]partsocrText.Split(-);stringprefixparts[0];// ABCstringnumberparts[1];// 12345Console.WriteLine($前缀{prefix}编号{number});}六新手常见坑总结字符串不可变每次“修改”都是创建新对象循环里拼接用 StringBuilder索引从0开始Substring(3) 是从第4个字符开始取跟数组一样空字符串和null不一样string s “” 和 string s null 是两码事用之前最好检查一下Contains 区分大小写默认是区分大小写的“ABC”.Contains(“abc”) 返回 false格式化数字注意文化差异有些国家用逗号当小数点视觉项目里最好指定不变的区域性InvariantCulture。七小练习试试自己写一下定义一个字符串 “100,200,150,180,220”用 Split 拆成数组计算平均值用 $ 插值格式化输出“5个尺寸的平均值是xxx.xx mm”保留2位小数用 StringBuilder 拼接1000条检测记录每条格式为 “第X个产品OK/NG”。