iOS原生开发展示数学公式的问题

最近遇到的问题,需求是展示服务端返回的一些文案,这是多么一个简单的展示啊,but偏偏出现了问题,因为返回的数据是包含有一些数学公式的,但是返回的数据是这个样子的

皮尔逊相似度是一种用于衡量两个变量之间线性相关程度的统计方法。其公式为:\[ r = \frac{\sum{(x_i - \bar{x})(y_i - \bar{y})}}{\sqrt{\sum{(x_i - \bar{x})^2} \sum{(y_i - \bar{y})^2}}} \]

要求把返回的公式进行按照对应的数学公式进行显示,好吧,那只能翻箱倒柜去查查资料了,根据简书、deepseek、腾讯元宝、chatgpt等等多种ai工具的回复,有三种解决方案

1、基于wkwebview进行展示,这种是开发成本最低的一种,比较简单

//你的包含latex公式的文本
NSString * text = @"";

// 构建包含MathJax的HTML字符串
NSString *htmlString = [NSString stringWithFormat:<!DOCTYPE html><html><head>    <meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>    <script type='text/javascript' async src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML'></script></head><body>    <div id='math'>%@</div>    <script type='text/javascript'>        MathJax.Hub.Queue(['Typeset', MathJax.Hub, 'math']);    </script></body></html>, text];       

// 加载HTML字符串
[webView loadHTMLString:htmlString baseURL:nil]

2、第二种发现了一种第三方sdk,iosMath库:https://github.com/kostub/iosMath,比较开心的去接入,开始进行coding,结果发现写了一堆代码,只展示了公式内容,其他文本相关的一点没有展示,如果只能展示公式相关的话,那只能说自己去做字符串的拆分,然后把普通文本和公式文本组成富文本去展示了


展示效果

字符串替换:发现iosMath不支持\(、\)、\[、\]这种类型的语法,然后把这种字符串替换为$符号

- (NSString *)replaceForLaTeXOriString:(NSString *)oldValue{

    //iosMath不支持\(、\)、\[、\],将这两种转为$来匹配

    NSString * pattern = @"(\\\\\\))|(\\\\\\()|(\\\\\\[\\s*)|(\\s*\\\\])";


    NSError*error =nil;

    // 创建正则表达式对象

    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];

    // 执行替换,将匹配到的模式替换为 $

    NSString * newValue = [regex stringByReplacingMatchesInString:oldValue options:0 range:NSMakeRange(0, oldValue.length) withTemplate:@"$"];

    returnnewValue;

}

字符串切割:

- (NSAttributedString *)attributedStringWithLeTeXString:(NSString *)text font:(UIFont *)font textColor:(UIColor *)textColor maxWidth:(CGFloat)maxWidth{

    self.maxWidth = maxWidth;

    text = [self replaceForLaTeXOriString:text];

    NSArray * tmpArr = [self matchString:text toRegexString:@"\\$.*?\\$"];

    NSMutableAttributedString * totalAttrString = [[NSMutableAttributedString alloc] init];

    for (KGLaTeXModel * model in tmpArr) {

        NSMutableAttributedString * attrString;

        if (model.isLaTeX) {

            attrString = [self getMaxLatexWithString:model.text font:font textColor:textColor].mutableCopy;

        }

        if (attrString) {

            [totalAttrString appendAttributedString:attrString];

        }else{

            attrString = [[NSMutableAttributedString alloc] initWithString:model.text];

            [attrString addAttributes:@{

                NSFontAttributeName : font,

                NSForegroundColorAttributeName : textColor,

            } range:NSMakeRange(0, model.text.length)];

            [totalAttrString appendAttributedString:attrString];

        }

    }

    return totalAttrString;

}

把文本根据$xxxx$做分割成不同的字符串

- (NSArray *)matchString:(NSString *)string toRegexString:(NSString *)regexStr{


    if(string.length == 0){

        return nil;

    }


    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexStr options:NSRegularExpressionCaseInsensitive error:nil];


    NSArray * matches = [regex matchesInString:string options:0 range:NSMakeRange(0, [string length])];


    //match: 所有匹配到的字符,根据() 包含级


    NSMutableArray *array = [NSMutableArray array];


    NSInteger location = 0;


    for (NSTextCheckingResult *match in matches) {

        //以正则中的(),划分成不同的匹配部分

        if (match.range.location == NSNotFound) {

            continue;

        }


        if (match.range.location != location) {

            NSRange range = NSMakeRange(location, match.range.location - location);

            KGLaTeXModel * model = [[KGLaTeXModel alloc] init];

            model.text = [string substringWithRange:range];

            model.range = range;

            model.isLaTeX = NO;

            [array addObject:model];

        }

        KGLaTeXModel * model = [[KGLaTeXModel alloc] init];

        model.text = [string substringWithRange:match.range];

        model.range = match.range;

        model.isLaTeX = YES;

        [array addObject:model];

        location = match.range.location + match.range.length;

    }


    if (location != string.length - 1) {

        NSRange range = NSMakeRange(location, string.length - location);

        KGLaTeXModel * model = [[KGLaTeXModel alloc] init];

        model.text = [string substringWithRange:range];

        model.range = range;

        model.isLaTeX = NO;

        [array addObject:model];

    }


    return array;

}

把latex公式文本转成富文本

- (NSAttributedString*)getMaxLatexWithString:(NSString*)latexStr  font:(UIFont*)fonttextColor:(UIColor*)textColor{


    MTMathUILabel* label = [[MTMathUILabel alloc] init];

    label.fontSize= font.pointSize;

    label.textColor= textColor;

    label.latex= latexStr;


    CGSizesize = [labelsizeThatFits:CGSizeMake(self.maxWidth,MAXFLOAT)];

    if(CGSizeEqualToSize(size,CGSizeZero)) {

        returnnil;

    }

    label.frame=CGRectMake(0,0, size.width, size.height);


    UIView* view = [[UIViewalloc]initWithFrame:CGRectMake(0,0, size.width, size.height+5)];

    [viewaddSubview:label];

    label.frame=CGRectMake(0,0, size.width, size.height);


    NSTextAttachment * attach = [[NSTextAttachment alloc] init];

    attach.bounds = CGRectMake(0, -view.frame.size.height/2.0, view.frame.size.width, view.frame.size.height);

    attach.image= [selfimageWithView:viewsize:view.frame.size];

    return [NSAttributedString attributedStringWithAttachment:attach];

}

调用方式:

    NSAttributedString * attrString = [GetLaTeXTool attributedStringWithLeTeXString:@"你的文本" font:[UIFont systemFontOfSize:15 weight:UIFontWeightMedium] textColor:UIColor.orangeColor maxWidth:300];

    self.label.attributedText= attrString;

我这边用到的文本,数学公式、化学公式、物理公式

    self.textArray = @[

        @"\\[\n  4\\text{Fe} + 3\\text{O}_2 \\rightarrow 2\\text{Fe}_2\\text{O}_3\n  \\]\n",

        @"\\[ g = \\frac{G \\cdot M}{R^2} \\]\n\n",

        @"\\[ (i\\gamma^\\mu \\partial_\\mu - m)\\psi = 0 \\]\n\n",

        @"$ \\because a==b $",

        @"皮尔逊相似度是一种用于衡量两个变量之间线性相关程度的统计方法。",

        @"其公式为:\n\n",

        @"\\[ r = \\frac{\\sum{(x_i - \\bar{x})(y_i - ",

        @"\\bar{y})}}{\\sqrt{\\sum{(x_i - \\bar{x})^2} \\sum{(y_i - \\bar{y})^2}}} \\]\n\n",

        @"其中:\n",

        @"- \\( x_i \\) 和 \\( y_i \\)分别是两个变量的观测值。\n",

        @"- \\( \\bar{x} \\) 和 \\( \\bar{y} \\) 分别是两个变量的平均值。\n",

        @"- \\( r \\) 的取值范围为 -1 到 1,1 表示完全正相关,",

        @"-1 表示完全负相关,",

        @"0 表示无线性相关。\n\n",

        @"皮尔逊相似度常用于统计分析、推荐系统等领域,",

        @"用来评估变量之间的线性关系。",

    ];

如果遇到了一些不支持的符号,可以通过下边这个方法去添加

比如说because不支持,$ \\because a==b $无法正常展示

[self addLatexSymbol:@"because" andEscapedString:@"∵"];

- (void)addLatexSymbol:(NSString*)symbolandEscapedString:(NSString*)escapedString{

    //添加iosMath一些不支持的转义字符

    [MTMathAtomFactory addLatexSymbol:symbol value:[MTMathAtomFactory operatorWithName:escapedString limits:NO]];

}

基本上完事了

3、第三种方案,我看推荐的是使用CoreText,因本人水平有限,就不巴巴了

4、swiftUI有一个LaTeXSwiftUI库,这个库有个限制就是最低得iOS16版本才行


有需要的可以下载下我写的demo:https://github.com/371726787/latexForTest

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容