最近遇到的問(wèn)題,需求是展示服務(wù)端返回的一些文案,這是多么一個(gè)簡(jiǎn)單的展示啊,but偏偏出現(xiàn)了問(wèn)題,因?yàn)榉祷氐臄?shù)據(jù)是包含有一些數(shù)學(xué)公式的,但是返回的數(shù)據(jù)是這個(gè)樣子的
皮爾遜相似度是一種用于衡量?jī)蓚€(gè)變量之間線性相關(guān)程度的統(tǒng)計(jì)方法。其公式為:\[ r = \frac{\sum{(x_i - \bar{x})(y_i -?\bar{y})}}{\sqrt{\sum{(x_i - \bar{x})^2} \sum{(y_i - \bar{y})^2}}} \]
要求把返回的公式進(jìn)行按照對(duì)應(yīng)的數(shù)學(xué)公式進(jìn)行顯示,好吧,那只能翻箱倒柜去查查資料了,根據(jù)簡(jiǎn)書、deepseek、騰訊元寶、chatgpt等等多種ai工具的回復(fù),有三種解決方案
1、基于wkwebview進(jìn)行展示,這種是開發(fā)成本最低的一種,比較簡(jiǎn)單
//你的包含latex公式的文本
NSString * text = @"";// 構(gòu)建包含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、第二種發(fā)現(xiàn)了一種第三方sdk,iosMath庫(kù):https://github.com/kostub/iosMath,比較開心的去接入,開始進(jìn)行coding,結(jié)果發(fā)現(xiàn)寫了一堆代碼,只展示了公式內(nèi)容,其他文本相關(guān)的一點(diǎn)沒(méi)有展示,如果只能展示公式相關(guān)的話,那只能說(shuō)自己去做字符串的拆分,然后把普通文本和公式文本組成富文本去展示了
字符串替換:發(fā)現(xiàn)iosMath不支持\(、\)、\[、\]這種類型的語(yǔ)法,然后把這種字符串替換為$符號(hào)
- (NSString *)replaceForLaTeXOriString:(NSString *)oldValue{
? ? //iosMath不支持\(、\)、\[、\],將這兩種轉(zhuǎn)為$來(lái)匹配
? ? NSString * pattern = @"(\\\\\\))|(\\\\\\()|(\\\\\\[\\s*)|(\\s*\\\\])";
? ? NSError*error =nil;
? ? // 創(chuàng)建正則表達(dá)式對(duì)象
? ? NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
? ? // 執(zhí)行替換,將匹配到的模式替換為 $
? ? 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;
}
把文本根據(jù)$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: 所有匹配到的字符,根據(jù)() 包含級(jí)
? ? 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公式文本轉(zhuǎn)成富文本
- (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];
}
調(diào)用方式:
? ? NSAttributedString * attrString = [GetLaTeXTool attributedStringWithLeTeXString:@"你的文本" font:[UIFont systemFontOfSize:15 weight:UIFontWeightMedium] textColor:UIColor.orangeColor maxWidth:300];
? ? self.label.attributedText= attrString;
我這邊用到的文本,數(shù)學(xué)公式、化學(xué)公式、物理公式
? ? 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 $",
? ? ? ? @"皮爾遜相似度是一種用于衡量?jī)蓚€(gè)變量之間線性相關(guān)程度的統(tǒng)計(jì)方法。",
? ? ? ? @"其公式為:\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 \\)分別是兩個(gè)變量的觀測(cè)值。\n",
? ? ? ? @"- \\( \\bar{x} \\) 和 \\( \\bar{y} \\) 分別是兩個(gè)變量的平均值。\n",
? ? ? ? @"- \\( r \\) 的取值范圍為 -1 到 1,1 表示完全正相關(guān),",
? ? ? ? @"-1 表示完全負(fù)相關(guān),",
? ? ? ? @"0 表示無(wú)線性相關(guān)。\n\n",
? ? ? ? @"皮爾遜相似度常用于統(tǒng)計(jì)分析、推薦系統(tǒng)等領(lǐng)域,",
? ? ? ? @"用來(lái)評(píng)估變量之間的線性關(guān)系。",
? ? ];
如果遇到了一些不支持的符號(hào),可以通過(guò)下邊這個(gè)方法去添加
比如說(shuō)because不支持,$ \\because a==b $無(wú)法正常展示
[self addLatexSymbol:@"because" andEscapedString:@"∵"];
- (void)addLatexSymbol:(NSString*)symbolandEscapedString:(NSString*)escapedString{
? ? //添加iosMath一些不支持的轉(zhuǎn)義字符
? ? [MTMathAtomFactory addLatexSymbol:symbol value:[MTMathAtomFactory operatorWithName:escapedString limits:NO]];
}
基本上完事了
3、第三種方案,我看推薦的是使用CoreText,因本人水平有限,就不巴巴了
4、swiftUI有一個(gè)LaTeXSwiftUI庫(kù),這個(gè)庫(kù)有個(gè)限制就是最低得iOS16版本才行
有需要的可以下載下我寫的demo:https://github.com/371726787/latexForTest