ios - Swift:内联显示(LaTeX)数学表达式
问题描述
我想在文本中显示数学术语,特别是在内联模式下,即在句子中。
例如,使用 LaTeX,这看起来像:“给定一个直角三角形,其长度为 \(a\),分别为 \(b\),斜边的长度为 \(c\),我们有 \[a^2 + b^2 = c^2.\] 这个事实被称为勾股定理。”
有人知道如何在 Swift 中实现这一点吗?
(我知道这个例子可以不用类似 LaTeX 的工具在 Swift 中实现。但是,我脑海中的表达其实比这个例子更复杂,我确实需要 LaTeX 的力量。)
最佳方式是一个UITextView
类,它可以识别数学分隔符 \(,\) resp。\[,\] 识别这些分隔符内的 LaTeX 代码,并相应地格式化文本。
在可汗学院应用程序中,这个问题似乎得到了解决,因为 Apple App Store/Google Play Store 中的屏幕截图显示了内联 (LaTeX) 数学。
我找到了包 iosMath ,它提供了一个 -like UILabel
class MTMathUILabel
。由于此类只能显示公式,因此这似乎不足以满足我的目的,除非有一种方法采用 LaTeX 源文本(例如上面的示例),将诸如 \(a\) 之类的表达式格式化为 tiny MTMathUILabel
s并在其他文本组件之间设置这些标签。由于我是 Swift 新手,我不知道这是否以及如何实现。此外,从印刷的角度来看,这似乎非常困难,因为换行肯定会出现困难。如果屏幕上同时出现大量此类标签,可能会出现性能问题?
可以使用 a 和 MathJax 或 KaTeX 来实现我想要的WKWebView
,当然这也是一种 hack。这会导致其他困难,例如,如果想要WKWebView
在屏幕上设置几个这样的 s,例如在UITableViewCell
s 内。
解决方案
使用 iosMath,我关于如何让 UILabel 具有内联 LaTeX 的解决方案是包含没有空格的 LATEX 和 ENDLATEX 标记。我用 MTMathUILabel 的图像替换了所有范围,从最后一个范围到第一个范围,这样位置就不会搞砸(这个解决方案允许多个标记)。从我的函数返回的图像被翻转,因此我使用了 .downMirrored 方向,并调整了它的大小以适合我的文本,因此您可能需要稍微修正一下翻转比例为 2.5 的数字和 attachment.bounds 的 y 值。
import UIKit
import iosMath
let question = UILabel()
let currentQuestion = "Given a right triangle having catheti of length LATEX(a)ENDLATEX resp. LATEX(b)ENDLATEX and a hypotenuse of length LATEX(c)ENDLATEX, we have LATEX[a^2 + b^2 = c^2]ENDLATEX. This fact is known as the Pythagorean theorem."
question.text = currentQuestion
if (question.text?.contains("LATEX"))! {
let tempString = question.text!
let tempMutableString = NSMutableAttributedString(string: tempString)
let pattern = NSRegularExpression.escapedPattern(for: "LATEX")
let regex = try? NSRegularExpression(pattern: pattern, options: [])
if let matches = regex?.matches(in: tempString, options: [], range: NSRange(location: 0, length: tempString.count)) {
var i = 0
while i < matches.count {
let range1 = matches.reversed()[i+1].range
let range2 = matches.reversed()[i].range
let finalDistance = range2.location - range1.location + 5
let finalRange = NSRange(location: range1.location, length: finalDistance)
let startIndex = String.Index(utf16Offset: range1.location + 5, in: tempString)
let endIndex = String.Index(utf16Offset: range2.location - 3, in: tempString)
let substring = String(tempString[startIndex..<endIndex])
var image = UIImage()
image = imageWithLabel(string: substring)
let flip = UIImage(cgImage: image.cgImage!, scale: 2.5, orientation: .downMirrored)
let attachment = NSTextAttachment()
attachment.image = flip
attachment.bounds = CGRect(x: 0, y: -flip.size.height/2 + 10, width: flip.size.width, height: flip.size.height)
let replacement = NSAttributedString(attachment: attachment)
tempMutableString.replaceCharacters(in: finalRange, with: replacement)
question.attributedText = tempMutableString
i += 2
}
}
}
func imageWithLabel(string: String) -> UIImage {
let label = MTMathUILabel()
label.latex = string
label.sizeToFit()
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0)
defer { UIGraphicsEndImageContext() }
label.layer.render(in: UIGraphicsGetCurrentContext()!)
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
推荐阅读
- if-statement - 谷歌表格中的排名
- javascript - 如何修复同时加载两个组件的错误?
- reactjs - 如何使用酶和玩笑测试 css 属性?
- algorithm - 是否可以在 O(logn) 中测试一个数字是否为素数?
- django - 尝试向 DRF API 发布一些信息,但使用 Python 请求遇到 403 禁止错误
- perl - 如何 grep 特定名称模式的文件?
- c# - 检测您是在调试中运行还是在运行时发布可执行文件
- webpack - 如何在 webpack 中实现 grunt processhtml 的确切行为?
- java - 带有 NoSuchMethodError 的 Mysql 连接器/j 驱动程序的 Kotlin Class.forName 失败
- angular - 如何动态更改剑道网格行中的货币