Как проверить, является ли символ границей слова

#swift #unicode #swift3

#swift #Юникод #swift3

Вопрос:

Как мне проверить, является ли a Character границей слова (как определено в Unicode TR # 29)?

У меня есть решение с использованием регулярного выражения, но я думаю, что это некрасиво.

Комментарии:

1. Дорогой бог только что посмотрел на эту спецификацию. Я никогда не задумывался, насколько сложной может быть такая простая задача

2. @AlexanderMomchliov: Если вы знакомы с регулярными выражениями, вы можете вспомнить b , что звучит обманчиво просто. Как только вы понимаете, что он определен таким образом, который полностью и совершенно непригоден для любого приложения на человеческом языке, вы начинаете искать хорошую замену, а затем замечаете, что язык сложный , действительно сложный 😉 Проблема Unicode заключается в том, что спецификации и алгоритмы, которые они разрабатывают, должны работатьдля всех используемых языков и даже для тех, которые не являются. Я думаю, что почти все простые проблемы с текстом таковы.

3. @fpg1503: может быть, для Swift есть привязка ICU, или у Apple есть что-то похожее как часть ее основных API. Хотя я немного сомневаюсь в этом; такие вещи, как правило, не реализуются в стандартных библиотеках.

Ответ №1:

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

Возможно, этот код будет полезен для вас. Он создает массив границ слова для заданной строки. Он основан на NSString.enumerateSubstrings(в:options:using:).

Вы можете запустить его в Playground:

 import Foundation

let str = "The quick brown_fox jumps over / the lazy dog. Flag 🇺🇸  Emoji 😎🤒 😱  ."

extension String {

    public var wordBoundaries: [String.Index] {

        var boundaries: [String.Index] = []

        let start = startIndex
        let end = endIndex
        boundaries.append(start)

        enumerateSubstrings(in: start ..< end, options: .byWords) {
                    substring, substringRange, enclosingRange, stop in

            let lb = substringRange.lowerBound
            if boundaries.last! != lb {
                boundaries.append(substringRange.lowerBound)
            }
            boundaries.append(substringRange.upperBound)
        }
        if boundaries.last! != end {
            boundaries.append(end)
        }

        return boundaries
    }
}


var prevBoundary: String.Index? = nil
for b in str.wordBoundaries {
    if let lower = prevBoundary {
        let s = str[lower ..< b]
        print(s)
    }
    prevBoundary = b
}