@@ -144,6 +144,21 @@ fn latex_template(content: &str) -> String {
144144/// 在程序生命周期内只编译一次,类似 C++ 中静态编译的正则模式
145145static MATH_TOKEN_REGEX : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"(\{MATH\d+\})" ) . unwrap ( ) ) ;
146146
147+ /// HTML 标签正则表达式
148+ /// 匹配 <br> 或 <br/> 换行标签
149+ static HTML_BR_REGEX : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"<br\s*/?>" ) . unwrap ( ) ) ;
150+
151+ /// 匹配 <img ...> 标签
152+ /// 提取 src、alt、width 属性
153+ /// 使用非贪婪匹配 .*? 捕获属性值,支持双引号或单引号
154+ /// C++ 中类似的模式匹配需要手写解析器,而 Rust 可以直接用正则
155+ static HTML_IMG_REGEX : Lazy < Regex > =
156+ Lazy :: new ( || Regex :: new ( r#"<img\s+[^>]*src\s*=\s*["']([^"']+)["'][^>]*>"# ) . unwrap ( ) ) ;
157+
158+ /// 提取 img 标签中所有属性的正则(用于获取 alt 和 width)
159+ static HTML_IMG_ATTR_REGEX : Lazy < Regex > =
160+ Lazy :: new ( || Regex :: new ( r#"(\w+)\s*=\s*["']([^"']*)["']"# ) . unwrap ( ) ) ;
161+
147162/// 将 Markdown 事件转换为 LaTeX
148163/// 这类似于 C++ 中的 Visitor 模式
149164fn convert_markdown_to_latex (
@@ -310,6 +325,84 @@ fn convert_markdown_to_latex(
310325 Event :: End ( TagEnd :: Link ) => {
311326 latex_content. push ( '}' ) ;
312327 }
328+ // HTML 标签处理:<br>、<img> 等
329+ Event :: Html ( html) | Event :: InlineHtml ( html) => {
330+ let html_str = html. trim ( ) ;
331+
332+ // 处理 <br> 换行标签
333+ if HTML_BR_REGEX . is_match ( html_str) {
334+ latex_content. push_str ( "\\ newline " ) ;
335+ continue ;
336+ }
337+
338+ // 处理 <img> 标签
339+ if let Some ( caps) = HTML_IMG_REGEX . captures ( html_str) {
340+ let src = caps. get ( 1 ) . map ( |m| m. as_str ( ) ) . unwrap_or ( "" ) ;
341+
342+ // 使用另一个正则提取所有属性
343+ let mut alt = String :: new ( ) ;
344+ let mut width = String :: new ( ) ;
345+
346+ for attr_cap in HTML_IMG_ATTR_REGEX . captures_iter ( html_str) {
347+ let attr_name = attr_cap. get ( 1 ) . map ( |m| m. as_str ( ) ) . unwrap_or ( "" ) ;
348+ let attr_value = attr_cap. get ( 2 ) . map ( |m| m. as_str ( ) ) . unwrap_or ( "" ) ;
349+
350+ match attr_name {
351+ "alt" => alt = attr_value. to_string ( ) ,
352+ "width" => width = attr_value. to_string ( ) ,
353+ _ => { }
354+ }
355+ }
356+
357+ // 转换宽度值
358+ let width_bracket = if !width. is_empty ( ) {
359+ // 处理不同的 width 格式:
360+ // - "50%" -> 转换为 0.5
361+ // - "0.5" -> 直接使用
362+ // - "100px" -> 忽略单位,简单处理
363+ let clean_width = width
364+ . trim_end_matches ( "px" )
365+ . trim_end_matches ( "%" )
366+ . trim ( )
367+ . to_string ( ) ;
368+
369+ if width. ends_with ( '%' ) {
370+ // 百分比格式:50% -> 0.5
371+ if let Ok ( pct) = clean_width. parse :: < f64 > ( ) {
372+ format ! ( "[width={}\\ textwidth]" , pct / 100.0 )
373+ } else {
374+ "[width=0.8\\ textwidth]" . to_string ( )
375+ }
376+ } else if let Ok ( num) = clean_width. parse :: < f64 > ( ) {
377+ // 纯数字:0.5 -> [width=0.5\textwidth]
378+ if num <= 1.0 {
379+ format ! ( "[width={}\\ textwidth]" , num)
380+ } else {
381+ // 如果 >1,可能是像素值或其他单位,默认使用 0.8
382+ "[width=0.8\\ textwidth]" . to_string ( )
383+ }
384+ } else {
385+ // 无法解析,默认使用 0.8
386+ "[width=0.8\\ textwidth]" . to_string ( )
387+ }
388+ } else {
389+ // 没有 width 属性,默认使用 0.8
390+ "[width=0.8\\ textwidth]" . to_string ( )
391+ } ;
392+
393+ // 生成 LaTeX 图片环境
394+ latex_content. push_str ( "\n \\ begin{figure}[htbp]\n \\ centering\n " ) ;
395+ latex_content
396+ . push_str ( & format ! ( "\\ includegraphics{}{{{}}}" , width_bracket, src) ) ;
397+
398+ if !alt. is_empty ( ) {
399+ latex_content. push_str ( & format ! ( "\n \\ caption{{{}}}" , escape_latex( & alt) ) ) ;
400+ }
401+
402+ latex_content. push_str ( "\n \\ end{figure}\n \n " ) ;
403+ }
404+ // <u> 和 </u> 标签暂时忽略
405+ }
313406 // 其他事件:忽略
314407 _ => { }
315408 }
0 commit comments