1.先利用投屏,把手机的单词投屏到电脑上,然后使用C#保存投屏截图 ,对一个单词截图进行保存
2.利用Halcon OCR识别 单词截图,保存单词文本
3.根据单词文本,进行http访问,保存词义词源
下面截图是我初步完成的时候,功能是正常的,后续可以根据自己想法改动或者优化,比如自动生成一个txt文档的单词表,

第一步 C#截图程序:
截图的时候要看一下位置到底对不对,结合屏幕分辨率设定截取的位置和大小,比如我的屏幕分辨率是1920*1080,我把投屏放在左下角,我的截屏位置就可以靠近1080。实际上代码中我使用的是:

可以先保存下来看看。
cs
public static class ScreenCaptureHelper
{
// 声明 Windows API 函数
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
// 定义 RECT 结构体
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
/// <summary>
/// 捕获屏幕指定区域并保存为图片文件
/// </summary>
public static bool CaptureAndSave(int x, int y, int width, int height,
string filePath, ImageFormat format = null)
{
if (format == null) format = ImageFormat.Png;
try
{
using (Bitmap bitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height));
}
string directory = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(directory))
{
Directory.CreateDirectory(directory);
}
bitmap.Save(filePath, format);
}
return true;
}
catch (Exception ex)
{
MessageBox.Show($"截图失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
/// <summary>
/// 通过窗口标题查找并捕获窗口
/// </summary>
/// <param name="windowTitle">窗口标题(部分匹配)</param>
/// <param name="filePath">保存路径</param>
/// <param name="format">图片格式</param>
/// <returns>是否成功</returns>
public static bool CaptureWindowByTitle(string windowTitle, string filePath, ImageFormat format = null)
{
// 查找窗口句柄
IntPtr hWnd = FindWindow(null, windowTitle);
if (hWnd == IntPtr.Zero)
{
MessageBox.Show($"未找到标题为 '{windowTitle}' 的窗口", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
return CaptureWindowByHandle(hWnd, filePath, format);
}
/// <summary>
/// 通过窗口句柄捕获窗口
/// </summary>
public static bool CaptureWindowByHandle(IntPtr hWnd, string filePath, ImageFormat format = null)
{
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("窗口句柄无效", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
// 获取窗口矩形区域
RECT rect = new RECT();
if (!GetWindowRect(hWnd, ref rect))
{
MessageBox.Show("获取窗口位置失败", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
int width = rect.Right - rect.Left;
int height = rect.Bottom - rect.Top;
if (width <= 0 || height <= 0)
{
MessageBox.Show("窗口尺寸无效", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
return CaptureAndSave(rect.Left, rect.Top, width, height, filePath, format);
}
/// <summary>
/// 捕获当前活动窗口
/// </summary>
public static bool CaptureActiveWindow(string filePath, ImageFormat format = null)
{
IntPtr hWnd = GetForegroundWindow();
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("未找到活动窗口", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
return CaptureWindowByHandle(hWnd, filePath, format);
}
/// <summary>
/// 获取当前活动窗口的标题
/// </summary>
public static string GetActiveWindowTitle()
{
IntPtr hWnd = GetForegroundWindow();
if (hWnd == IntPtr.Zero) return string.Empty;
System.Text.StringBuilder sb = new System.Text.StringBuilder(256);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
}
第二步 Halcon程序:
需要先根据单词的字母进行训练,我选取了几个单词,确保这些单词字母组合起来涵盖了26个字母。

编写第一个 Halcon程序 ----训练程序
训练这些字母,生成训练文件和分类器:
个人理解:
训练文件保存的是每一个字母和对应的图像特征;
分类器里面有图像特征到字母映射关系,这样就可以实现:传入一个图像特征,依赖分类器返回对应的字符;

这里参考了Halcon例程:


我贴出来我的halcon代码供参考:
Matlab
*
* OCR (Training)
*
dev_close_window ()
dev_update_off ()
* Train Font 'arial'
FontName := 'arial'
FontImages := ['acknowledge','browse','gangster','jumble','laziness','naked','overall','pacify','quiver','theft','xerox']
NumImages := |FontImages|
read_image (Image,'D:/TheCodeWrittenByOneselfOrFromOthers/HalconOcr/TrainingImage/'+FontImages[0]+'.png')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowID)
set_display_font (WindowID, 16, 'mono', 'true', 'false')
dev_display (Image)
dev_update_off ()
* ---------- Characters to be recognized ----------
* for I := 0 to 25 by 1
* Char[I] := chr(round(I + ord('A')))
* endfor
* for I := 0 to 25 by 1
* Char[I + 26] := chr(round(I + ord('a')))
* endfor
* for I := 0 to 9 by 1
* Char[I + 52] := chr(round(I + ord('0')))
* endfor
* ---------- Segment characters ----------
dev_set_check ('~give_error')
delete_file (FontName + '.trf')
dev_set_check ('give_error')
gen_empty_obj (TrainImage)
gen_empty_obj (TrainRegion)
dev_set_colored (12)
dev_set_draw ('margin')
for I := 1 to NumImages by 1
read_image (Image,'D:/TheCodeWrittenByOneselfOrFromOthers/HalconOcr/TrainingImage/'+FontImages[I-1]+'.png')
rgb1_to_gray (Image, GrayImage)
Char := []
for i := 0 to strlen(FontImages[I-1])-1 by 1
tuple_substr(FontImages[I-1], i, i, SubChar)
Char := [Char, SubChar]
endfor
NumChar := |Char|
* 2. 提取字母区域 - 使用动态阈值
threshold (GrayImage, Region, 0, 150)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, Letters, 'area', 'and', 30, 10000)
* 先按Column排序
sort_region (Letters, LettersSorted, 'first_point', 'true', 'column')
* 获取排序后的中心坐标
area_center (LettersSorted, Area, Row, Column)
* 遍历合并相邻区域(Column相差5以内)
gen_empty_region (MergedRegions)
select_obj (LettersSorted, CurrentRegion, 1)
CurrentCol := Column[0]
for i := 2 to |Column| by 1
select_obj (LettersSorted, NextRegion, i)
if (Column[i-1] - CurrentCol <= 5)
union2 (CurrentRegion, NextRegion, CurrentRegion)
else
concat_obj (MergedRegions, CurrentRegion, MergedRegions)
CurrentRegion := NextRegion
CurrentCol := Column[i-1]
endif
endfor
concat_obj (MergedRegions, CurrentRegion, MergedRegions)
remove_obj (MergedRegions, MergedRegionsWithoutFirst, 1)
* 重新连通并筛选
* connection (MergedRegions, LettersConnected)
select_shape (MergedRegionsWithoutFirst, LettersFinal, 'area', 'and', 30, 5000)
sort_region (MergedRegionsWithoutFirst, Characters, 'first_point', 'true', 'column')
count_obj (Characters, Num)
if (Num == NumChar)
concat_obj (TrainImage, GrayImage, TrainImage)
concat_obj (TrainRegion, Characters, TrainRegion)
endif
dev_display (Image)
dev_display (Characters)
disp_message (WindowID, 'Segment characters', 'window', 12, 12, 'black', 'true')
append_ocr_trainf (Characters, GrayImage, Char, FontName + '.trf')
endfor
count_obj (TrainImage, NumImages)
disp_continue_message (WindowID, 'black', 'true')
stop ()
* ---------- Training of the OCR classifier ---------
dev_display (Image)
disp_message (WindowID, 'Train the font classifier', 'window', 12, 12, 'black', 'true')
Char := []
for I := 0 to 25 by 1
Char[I] := chr(round(I + ord('a')))
endfor
create_ocr_class_mlp (8, 10, 'constant', 'default', Char, 10, 'none', 10, 42, OCRHandle)
trainf_ocr_class_mlp (OCRHandle, FontName + '.trf', 200, 1, 0.01, Error, ErrorLog)
disp_continue_message (WindowID, 'black', 'true')
stop ()
* Check for correct classification
* dev_set_color ('green')
* for I := 1 to NumImages by 1
* select_obj (TrainImage, Image, I)
* copy_obj (TrainRegion, Characters, 1 + (I - 1) * NumChar, NumChar)
* dev_clear_window ()
* dev_display (Image)
* dev_set_color ('green')
* dev_display (Characters)
* disp_message (WindowID, 'Check result', 'window', 12, 12, 'black', 'true')
* do_ocr_multi_class_mlp (Characters, Image, OCRHandle, RecChar, Confidence)
* Char := []
* for i := 0 to strlen(FontImages[I-1])-1 by 1
* tuple_substr(FontImages[I-1], i, i, SubChar)
* Char := [Char, SubChar]
* endfor
* CheckDiff := ord(Char) [!=] ord(RecChar)
* select_mask_obj (Characters, WrongChar, CheckDiff)
* dev_set_color ('red')
* dev_display (WrongChar)
* disp_continue_message (WindowID, 'black', 'true')
* stop ()
* endfor
* ---------- Write OCR classifier ---------
write_ocr_class_mlp (OCRHandle, FontName)
编写第二个 Halcon程序 ----识别程序
就是依靠分类器进行识别字母的程序:
cs
* 关闭窗口更新
dev_update_off ()
* 1. 读取图像
read_image (Image, 'D:/TheCodeWrittenByOneselfOrFromOthers/HalconOcr/Screenshot_20260619_154428.png')
rgb1_to_gray (Image, GrayImage)
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (GrayImage)
* 2. 提取字母区域 - 使用动态阈值
threshold (GrayImage, Region, 0, 150)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, Letters, 'area', 'and', 30, 5000)
* 先按Column排序
sort_region (Letters, LettersSorted, 'first_point', 'true', 'column')
* 获取排序后的中心坐标
area_center (LettersSorted, Area, Row, Column)
* 遍历合并相邻区域(Column相差5以内)
gen_empty_region (MergedRegions)
select_obj (LettersSorted, CurrentRegion, 1)
CurrentCol := Column[0]
for i := 2 to |Column| by 1
select_obj (LettersSorted, NextRegion, i)
if (Column[i-1] - CurrentCol <= 5)
union2 (CurrentRegion, NextRegion, CurrentRegion)
else
concat_obj (MergedRegions, CurrentRegion, MergedRegions)
CurrentRegion := NextRegion
CurrentCol := Column[i-1]
endif
endfor
concat_obj (MergedRegions, CurrentRegion, MergedRegions)
remove_obj (MergedRegions, MergedRegionsWithoutFirst, 1)
select_shape (MergedRegionsWithoutFirst, LettersFinal, 'area', 'and', 30, 5000)
sort_region (MergedRegionsWithoutFirst, LettersSortedFinal, 'first_point', 'true', 'column')
* 3. 使用内置OCR
read_ocr_class_mlp ('D:/TheCodeWrittenByOneselfOrFromOthers/HalconOcr/arial.omc', OCRHandle)
do_ocr_multi_class_mlp (LettersSortedFinal, GrayImage, OCRHandle, Class, Confidence)
* 4. 将Class数组按照顺序组合成单词字符串
WordString := ''
for i := 0 to |Class| - 1 by 1
WordString := WordString + Class[i]
endfor
* 5. 释放OCR资源
clear_ocr_class_mlp (OCRHandle)
就是打开刚刚保存的分类器(omc文件),传入每一个字母的特征,返回对应的字符;
效果:

接下来导出C#代码,稍微改动一下传入图片地址,传出单词字符串:
cs
internal class FindWord
{
public static void action(string path,out string word)
{
word = string.Empty;
// Stack for temporary objects
HObject[] OTemp = new HObject[20];
// Local iconic variables
HObject ho_Image, ho_GrayImage, ho_Region;
HObject ho_ConnectedRegions, ho_Letters, ho_LettersSorted;
HObject ho_MergedRegions, ho_CurrentRegion, ho_NextRegion = null;
HObject ho_MergedRegionsWithoutFirst, ho_LettersFinal, ho_LettersSortedFinal;
// Local control variables
HTuple hv_Width = new HTuple(), hv_Height = new HTuple();
HTuple hv_WindowHandle = new HTuple(), hv_Area = new HTuple();
HTuple hv_Row = new HTuple(), hv_Column = new HTuple();
HTuple hv_CurrentCol = new HTuple(), hv_i = new HTuple();
HTuple hv_OCRHandle = new HTuple(), hv_Class = new HTuple();
HTuple hv_Confidence = new HTuple(), hv_WordString = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_GrayImage);
HOperatorSet.GenEmptyObj(out ho_Region);
HOperatorSet.GenEmptyObj(out ho_ConnectedRegions);
HOperatorSet.GenEmptyObj(out ho_Letters);
HOperatorSet.GenEmptyObj(out ho_LettersSorted);
HOperatorSet.GenEmptyObj(out ho_MergedRegions);
HOperatorSet.GenEmptyObj(out ho_CurrentRegion);
HOperatorSet.GenEmptyObj(out ho_NextRegion);
HOperatorSet.GenEmptyObj(out ho_MergedRegionsWithoutFirst);
HOperatorSet.GenEmptyObj(out ho_LettersFinal);
HOperatorSet.GenEmptyObj(out ho_LettersSortedFinal);
try
{
//1. 读取图像
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, path);
ho_GrayImage.Dispose();
HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage);
hv_Width.Dispose(); hv_Height.Dispose();
HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.CloseWindow(HDevWindowStack.Pop());
}
hv_WindowHandle.Dispose();
//2. 提取字母区域 - 使用动态阈值
ho_Region.Dispose();
HOperatorSet.Threshold(ho_GrayImage, out ho_Region, 0, 150);
ho_ConnectedRegions.Dispose();
HOperatorSet.Connection(ho_Region, out ho_ConnectedRegions);
ho_Letters.Dispose();
HOperatorSet.SelectShape(ho_ConnectedRegions, out ho_Letters, "area", "and",
30, 5000);
//先按Column排序
ho_LettersSorted.Dispose();
HOperatorSet.SortRegion(ho_Letters, out ho_LettersSorted, "first_point", "true",
"column");
//获取排序后的中心坐标
hv_Area.Dispose(); hv_Row.Dispose(); hv_Column.Dispose();
HOperatorSet.AreaCenter(ho_LettersSorted, out hv_Area, out hv_Row, out hv_Column);
//遍历合并相邻区域(Column相差5以内)
ho_MergedRegions.Dispose();
HOperatorSet.GenEmptyRegion(out ho_MergedRegions);
ho_CurrentRegion.Dispose();
HOperatorSet.SelectObj(ho_LettersSorted, out ho_CurrentRegion, 1);
hv_CurrentCol.Dispose();
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
hv_CurrentCol = hv_Column.TupleSelect(
0);
}
for (hv_i = 2; (int)hv_i <= (int)(new HTuple(hv_Column.TupleLength())); hv_i = (int)hv_i + 1)
{
ho_NextRegion.Dispose();
HOperatorSet.SelectObj(ho_LettersSorted, out ho_NextRegion, hv_i);
if ((int)(new HTuple((((hv_Column.TupleSelect(hv_i - 1)) - hv_CurrentCol)).TupleLessEqual(
5))) != 0)
{
{
HObject ExpTmpOutVar_0;
HOperatorSet.Union2(ho_CurrentRegion, ho_NextRegion, out ExpTmpOutVar_0
);
ho_CurrentRegion.Dispose();
ho_CurrentRegion = ExpTmpOutVar_0;
}
}
else
{
{
HObject ExpTmpOutVar_0;
HOperatorSet.ConcatObj(ho_MergedRegions, ho_CurrentRegion, out ExpTmpOutVar_0
);
ho_MergedRegions.Dispose();
ho_MergedRegions = ExpTmpOutVar_0;
}
ho_CurrentRegion.Dispose();
ho_CurrentRegion = new HObject(ho_NextRegion);
hv_CurrentCol.Dispose();
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
hv_CurrentCol = hv_Column.TupleSelect(
hv_i - 1);
}
}
}
{
HObject ExpTmpOutVar_0;
HOperatorSet.ConcatObj(ho_MergedRegions, ho_CurrentRegion, out ExpTmpOutVar_0
);
ho_MergedRegions.Dispose();
ho_MergedRegions = ExpTmpOutVar_0;
}
ho_MergedRegionsWithoutFirst.Dispose();
HOperatorSet.RemoveObj(ho_MergedRegions, out ho_MergedRegionsWithoutFirst,
1);
ho_LettersFinal.Dispose();
HOperatorSet.SelectShape(ho_MergedRegionsWithoutFirst, out ho_LettersFinal,
"area", "and", 30, 5000);
ho_LettersSortedFinal.Dispose();
HOperatorSet.SortRegion(ho_MergedRegionsWithoutFirst, out ho_LettersSortedFinal,
"first_point", "true", "column");
//3. 使用内置OCR
hv_OCRHandle.Dispose();
HOperatorSet.ReadOcrClassMlp("D:/TheCodeWrittenByOneselfOrFromOthers/HalconOcr/arial.omc",
out hv_OCRHandle);
hv_Class.Dispose(); hv_Confidence.Dispose();
HOperatorSet.DoOcrMultiClassMlp(ho_LettersSortedFinal, ho_GrayImage, hv_OCRHandle,
out hv_Class, out hv_Confidence);
//4. 将Class数组按照顺序组合成单词字符串
hv_WordString.Dispose();
hv_WordString = "";
for (hv_i = 0; (int)hv_i <= (int)((new HTuple(hv_Class.TupleLength())) - 1); hv_i = (int)hv_i + 1)
{
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_WordString = hv_WordString + (hv_Class.TupleSelect(
hv_i));
hv_WordString.Dispose();
hv_WordString = ExpTmpLocalVar_WordString;
}
}
}
word = hv_WordString;
//5. 释放OCR资源
HOperatorSet.ClearOcrClassMlp(hv_OCRHandle);
}
catch (HalconException HDevExpDefaultException)
{
ho_Image.Dispose();
ho_GrayImage.Dispose();
ho_Region.Dispose();
ho_ConnectedRegions.Dispose();
ho_Letters.Dispose();
ho_LettersSorted.Dispose();
ho_MergedRegions.Dispose();
ho_CurrentRegion.Dispose();
ho_NextRegion.Dispose();
ho_MergedRegionsWithoutFirst.Dispose();
ho_LettersFinal.Dispose();
ho_LettersSortedFinal.Dispose();
hv_Width.Dispose();
hv_Height.Dispose();
hv_WindowHandle.Dispose();
hv_Area.Dispose();
hv_Row.Dispose();
hv_Column.Dispose();
hv_CurrentCol.Dispose();
hv_i.Dispose();
hv_OCRHandle.Dispose();
hv_Class.Dispose();
hv_Confidence.Dispose();
hv_WordString.Dispose();
throw HDevExpDefaultException;
}
ho_Image.Dispose();
ho_GrayImage.Dispose();
ho_Region.Dispose();
ho_ConnectedRegions.Dispose();
ho_Letters.Dispose();
ho_LettersSorted.Dispose();
ho_MergedRegions.Dispose();
ho_CurrentRegion.Dispose();
ho_NextRegion.Dispose();
ho_MergedRegionsWithoutFirst.Dispose();
ho_LettersFinal.Dispose();
ho_LettersSortedFinal.Dispose();
hv_Width.Dispose();
hv_Height.Dispose();
hv_WindowHandle.Dispose();
hv_Area.Dispose();
hv_Row.Dispose();
hv_Column.Dispose();
hv_CurrentCol.Dispose();
hv_i.Dispose();
hv_OCRHandle.Dispose();
hv_Class.Dispose();
hv_Confidence.Dispose();
hv_WordString.Dispose();
}
}
第三步 访问Http,进行翻译:
这里的网址是我常用的一个网址,只是一个例程,说明了可以实现对应的需求:
cs
public async void Translate(string word)
{
List<string> outputLines = new List<string>();
// 生成格式:2026-06-19.txt
var fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
var outputFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
if (!File.Exists(outputFilePath))
{
//StreamWriter 自动创建
//File.Create(outputFilePath);
}
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
if (string.IsNullOrWhiteSpace(word))
{
return;
}
string trimmedWord = word.Trim();
string url = $"https://www.dictool.com/w/{trimmedWord}";
string meaning = string.Empty;
string etymology = string.Empty;
try
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
string htmlContent = await response.Content.ReadAsStringAsync();
// 解析HTML
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlContent);
// 获取词义 (id: yd-word-meaning)
HtmlNode meaningNode = doc.GetElementbyId("yd-word-meaning");
if (meaningNode != null)
{
meaning = meaningNode.InnerText.Trim();
this.txtTranslate.Text = meaning;
}
// 获取中文词源 (id: yd-ciyuan)
HtmlNode etymologyNode = doc.GetElementbyId("yd-ciyuan");
if (etymologyNode != null)
{
etymology = etymologyNode.InnerText.Trim();
// 移除开头的单词和空格(如 "mermaid 美人鱼" 中的 "mermaid ")
if (etymology.StartsWith(trimmedWord + " "))
{
etymology = etymology.Substring(trimmedWord.Length + 1);
this.txtSource.Text = etymology;
}
}
// 如果未找到词义,记录一个占位符
if (string.IsNullOrEmpty(meaning))
{
meaning = "[词义未找到]";
}
}
}
catch (HttpRequestException ex)
{
UpdateStatus($" 请求失败: {ex.Message}");
meaning = "[请求失败]";
etymology = string.Empty;
}
catch (Exception ex)
{
UpdateStatus($" 处理失败: {ex.Message}");
meaning = "[处理出错]";
etymology = string.Empty;
}
// 按照格式添加到输出行
outputLines.Add($"{trimmedWord}");
outputLines.Add($"{meaning}");
outputLines.Add(string.IsNullOrEmpty(etymology) ? "" : etymology);
}
using (StreamWriter writer = new StreamWriter(outputFilePath, true, Encoding.UTF8))
{
foreach (string line in outputLines)
{
await writer.WriteLineAsync(line);
}
}
}
效果:

