Кодирование цвета текста с помощью простого решения

Это вторая короткая статья, описывающая требования клиента и решение с помощью SwiftUI. Тестировалось на iOS 13, Swift 5.x.

Возможно, вы читали статью о Le Conjugator, которую я написал на прошлой неделе. Небольшой проект, чтобы помочь студентам выучить свои французские глаголы, что более важно, мне рассказали их времена глаголов и, самое главное, все правила спряжения, для указанных времен.

Я обдумывал идею создания пользовательской клавиатуры и в процессе разработал настоящее сенсорное управление [ссылка]. Работа, которой я гордился, но, к сожалению, в итоге оказалась бесполезной для проекта.

Настоящий вызов прибыл. У меня было десять тысяч спряжений, чтобы показать их во всей красе. Спряжения, некоторые из которых были правильными и неправильными; и какой-то смешанный мешок орехов или так казалось.

Задача состоит в том, чтобы отобразить глаголы как минимум в двух цветах, только те цвета, которые нужно разделить внутри слов. Позвольте привести пример.

Да, это снова глагол «avoir». Глагол настолько неправильный, насколько мне известно, этот глагол присутствует, как мне сказали. Давайте сделаем шаг назад и посмотрим на это как на компьютерного ученого, на текстовую строку. Вот некоторые из моих мыслей.

  • Я мог бы хранить текст в структурах многомерных массивов, но это было бы ужасно сложно и наверняка сломалось бы с каким-нибудь неприятным кельтским исключением.
  • Я мог бы сохранить номер столбца букв и длину букв, используемых в двух целых числах для каждого примера времени глагола. Я мог бы использовать набор целых чисел, если бы у меня было несколько разрывов; но подождите — это начало звучать как многомерная трясина.
  • Я мог бы просто сохранить копию букв, которые должны были быть красными, и проделать некоторую логику, когда я отображал их. Но нет, покерная мешанина со строками не слишком дружелюбна в свифте, это все-таки не PERL.

Ни одна из моих первоначальных идей не произвела на меня особого впечатления. Номер/длина письма были самыми близкими, но я был обеспокоен тем, что будет одно из тех исключений, которые раз в жизни заставят его взорваться [скорее всего, на глазах у клиента].

Я вывел собаку на прогулку и за это время придумал план. План, восходящий к моим корням, к тем классам ассемблера 6502. В старые добрые времена у нас не было мегабайт места для создания колоссальных головоломок кодирования, нет, у меня было всего 32 КБ в моем микрокомпьютере BBC. В те дни мы планировали использовать все до последнего бита. Вы вспоминаете биты, у вас 64 бита в UInt64. Возможно, в свое время вы тоже сталкивались с побитовыми операторами.

Таков был план. Я бы использовал UInt64 для хранения цвета моего текста для каждого времени глагола вместе с глаголом. Единственный UInt64, уровень сложности мне понравился. Если бы бит был равен 0, это означало бы, что он должен отображаться красным, а 1 означал бы, что он не будет черным.

Первая задача просто разбить мой текст на буквы и отобразить их.

struct ContentView: View {
  @State var word = "Hello,World"
  var body: some View {
  let letter = word.map( { String($0) } )
  return VStack {
    HStack(spacing:0) {
      ForEach((0 ..< letter.count), id: \.self) { column in
        Text(letter[column])
        .font(Fonts.futuraCondensedMedium(size: fontSize))
      }
    }
  }
}

Теперь все, что мне было нужно, это логика использования значения UInt64 в коде для определения цвета. Это должна быть функция, так как эта странная структура цикла SwiftUI. Я добавил этот код в цикл для вызова «colorCode».

.foregroundColor(colorCode(gate: Int(self.gate), no: column) ? Color.black: Color.red)

Логика проста, каждый раз, когда он проходит цикл, он перемещает свою битовую маску на один бит влево, чтобы увидеть, должен ли он быть красным или нет. Код выглядит так.

func colorCode(gate:Int, no:Int) -> Bool {
  let binaryColumn = 1 << no - 1
  let value = UInt64(gate) & UInt64(binaryColumn)
  return value > 0 ? true:false
}

Ключевым моментом здесь является преобразование номера столбца текстовых букв в двоичную битовую маску. Теперь, используя простую двоичную логику, я мог закодировать, как мой глагол будет выглядеть в одном UInt64. Если длина не превышает 64 символов (слава богу, мы не используем немецкий язык).

Вот таблица, показывающая первый запуск, здесь я показываю 16-битные числа в двоичном формате из-за ограничений ширины страницы. Буквы бегут по сторонам. Битовый шаблон для хранения букв, которые должны быть красными в первом столбце. Битовая комбинация во втором столбце, маска столбца. Последний результат побитового объединения их вместе. В примере начальная маска равна 1. Первая буква будет красной, остальные черными.

H bg  0000000000000001  bc  0000000000000000 0000000000000001
e bg  0000000000000001  bc  0000000000000001 0000000000000000
l bg  0000000000000001  bc  0000000000000010 0000000000000000
l bg  0000000000000001  bc  0000000000000011 0000000000000000
o bg  0000000000000001  bc  0000000000000100 0000000000000000
, bg  0000000000000001  bc  0000000000000101 0000000000000000
W bg  0000000000000001  bc  0000000000000110 0000000000000000
o bg  0000000000000001  bc  0000000000000111 0000000000000000
r bg  0000000000000001  bc  0000000000001000 0000000000000000
l bg  0000000000000001  bc  0000000000001001 0000000000000000
d bg  0000000000000001  bc  0000000000001010 0000000000000000

Мне нужно было сделать комплексный тест. Поэтому я добавил таймер к миксу. Теперь я мог последовательно кормить разные ворота/маски. Вот окончательный код. Нет, это люди POC, я не проверяю здесь высокие границы, в конце концов он взорвется — вас предупредили.

И вот оно. Мораль этой истории, убедитесь, что вы используете все части. Сохраняйте спокойствие, продолжайте кодировать.