aboutsummaryrefslogtreecommitdiff
path: root/iTexSnip/Utils/KatexUtils.swift
blob: 5daaf13bc6e6a6ab6a313a1296a8a702f37152fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
//  KatexUtils.swift
//  iTexSnip
//
//  Created by Navan Chauhan on 10/13/24.
//

import Foundation

func change(
  _ inputStr: String, oldInst: String, newInst: String, oldSurrL: Character, oldSurrR: Character,
  newSurrL: String, newSurrR: String
) -> String {
  var result = ""
  var i = 0
  let n = inputStr.count
  let inputArray = Array(inputStr)

  while i < n {
    if i + oldInst.count <= n
      && inputStr[
        inputStr.index(
          inputStr.startIndex, offsetBy: i)..<inputStr.index(
            inputStr.startIndex, offsetBy: i + oldInst.count)] == oldInst
    {
      let start = i + oldInst.count
      if start < n && inputArray[start] == oldSurrL {
        var count = 1
        var j = start + 1
        var escaped = false

        while j < n && count > 0 {
          if inputArray[j] == "\\" && !escaped {
            escaped = true
            j += 1
            continue
          }

          if inputArray[j] == oldSurrR && !escaped {
            count -= 1
            if count == 0 {
              break
            }
          } else if inputArray[j] == oldSurrL && !escaped {
            count += 1
          }

          escaped = false
          j += 1
        }

        if count == 0 {
          let innerContent = String(inputArray[(start + 1)..<j])
          result += newInst + newSurrL + innerContent + newSurrR
          i = j + 1
          continue
        } else {
          result += newInst + newSurrL
          i = start + 1
          continue
        }
      }
    }
    result.append(inputArray[i])
    i += 1
  }

  if oldInst != newInst && result.contains(oldInst + String(oldSurrL)) {
    return change(
      result, oldInst: oldInst, newInst: newInst, oldSurrL: oldSurrL, oldSurrR: oldSurrR,
      newSurrL: newSurrL, newSurrR: newSurrR)
  }

  return result
}

func findSubstringPositions(_ string: String, substring: String) -> [Int] {
  var positions: [Int] = []
  var searchRange = string.startIndex..<string.endIndex

  while let range = string.range(of: substring, options: [], range: searchRange) {
    let position = string.distance(from: string.startIndex, to: range.lowerBound)
    positions.append(position)
    searchRange = range.upperBound..<string.endIndex
  }

  return positions
}

func rmDollarSurr(content: String) -> String {
  let pattern = try! NSRegularExpression(pattern: "\\\\[a-zA-Z]+\\$.*?\\$|\\$.*?\\$", options: [])
  var newContent = content
  let matches = pattern.matches(
    in: content, options: [], range: NSRange(content.startIndex..<content.endIndex, in: content))

  for match in matches.reversed() {
    let matchedString = (content as NSString).substring(with: match.range)
    if !matchedString.starts(with: "\\") {
      let strippedMatch = matchedString.replacingOccurrences(of: "$", with: "")
      newContent = newContent.replacingOccurrences(of: matchedString, with: " \(strippedMatch) ")
    }
  }

  return newContent
}

func changeAll(
  inputStr: String, oldInst: String, newInst: String, oldSurrL: Character, oldSurrR: Character,
  newSurrL: String, newSurrR: String
) -> String {
  let positions = findSubstringPositions(inputStr, substring: oldInst + String(oldSurrL))
  var result = inputStr

  for pos in positions.reversed() {
    let startIndex = result.index(result.startIndex, offsetBy: pos)
    let substring = String(result[startIndex..<result.endIndex])
    let changedSubstring = change(
      substring, oldInst: oldInst, newInst: newInst, oldSurrL: oldSurrL, oldSurrR: oldSurrR,
      newSurrL: newSurrL, newSurrR: newSurrR)
    result.replaceSubrange(startIndex..<result.endIndex, with: changedSubstring)
  }

  return result
}

func toKatex(formula: String) -> String {
  var res = formula
  res = changeAll(
    inputStr: res, oldInst: "\\mbox ", newInst: " ", oldSurrL: "{", oldSurrR: "}", newSurrL: "",
    newSurrR: "")
  res = changeAll(
    inputStr: res, oldInst: "\\mbox", newInst: " ", oldSurrL: "{", oldSurrR: "}", newSurrL: "",
    newSurrR: "")

  res = res.replacingOccurrences(of: "\\[", with: "")
  res = res.replacingOccurrences(of: "\\]", with: "")
  res = res.replacingOccurrences(
    of: "\\\\[?.!,\'\"](?:\\s|$)", with: "", options: .regularExpression)

  res = rmDollarSurr(content: res)

  res = res.replacingOccurrences(of: " +", with: " ", options: .regularExpression)

  return res.trimmingCharacters(in: .whitespacesAndNewlines)
}