Почему последняя строка не удаляется из stringArray с использованием .map - PullRequest
0 голосов
/ 31 января 2019

Я использую Swift.Я пытаюсь преобразовать предложение в массив строк.Я использовал map, чтобы отделить точки и запятые от слова следующим образом:

extension String  {


func convertSentenceToArray()-> [String] {
var sentence = String(self)

sentence.index(of: ".").map { 
   sentence.remove( at: $0)
   sentence.insert(".", at: $0)
   sentence.insert(" ", at: $0)
   }
sentence.index(of: ",").map { 
  sentence.remove( at: $0)
  sentence.insert(",", at: $0)
  sentence.insert(" ", at: $0) 
   }
 return sentence.components(separatedBy: " ")
 }
}

let  thisSentenceString = "I am trying to create an array from a sentence. But I don't understand, Why isn't the last fullstop removed, from the last word."

let thisSentenceArray = thisSentenceString.convertSentenceToArray()

print(thisSentenceArray)

приводит к:

["I", "am", "пытаюсь", "на "," создать "," an "," массив "," из "," a "," предложение ",". "," Но "," I "," не \ "," понимать ",",", "Почему", "isn \ 't", "the", "last", "fullstop", "удалено", "from", "the", "last", «слово». ]

Все стопы и запятые обрабатываются так, как я ожидал, за исключением последнего.

Я не понимаю, почему последнийполная остановка остается.Хотя я могу найти обходной путь для этого, я хотел бы понять, что не так с выбранным мной подходом.

Ответы [ 4 ]

0 голосов
/ 16 февраля 2019

Вот более традиционный и общий подход:

func separateString(string: String) -> [String]{
    let stringArray = Array(string.unicodeScalars)
    var stringsArray: [String] = []

    let letterSet = CharacterSet.letters
    let punctuationSet = CharacterSet.punctuationCharacters

    var newWord = ""
    var newPunctioationChar = ""

    for char in stringArray {
        if letterSet.contains(char) {
            newWord.unicodeScalars.append(char)

        } else if punctuationSet.contains(char) {
            newPunctioationChar.unicodeScalars.append(char)

            stringsArray.append(contentsOf: [newWord, newPunctioationChar])

            newWord = ""
            newPunctioationChar = ""
        }
    }

     return stringsArray
}
0 голосов
/ 31 января 2019

Сначала объяснение того, что делает ваш код:

sentence
   .index(of: ".") // find the first index of the dot character
   .map {  // Optional.map, if the index exists, do the following
      sentence.remove( at: $0) // remove dot
      sentence.insert(".", at: $0) // insert dot again
      sentence.insert(" ", at: $0) // insert space
   }

или переписано:

if let firstDotIndex = sentence.index(of: ".") {
    sentence.insert(" ", at: firstDotIndex)
}

Это означает, что только первый символ точки найден и заменен.

Чтобы правильно выполнить этот алгоритм, вам понадобится:

// helper method checking punctuation to avoid code duplication
let isPunctuation: (Character) -> Bool = {
    return [".", ","].contains($0)
}

// initial range, we want to check the entire string
var range = sentence.startIndex...

// iterate while some punctuation exists
while let punctuationIndex = sentence[range].index(where: isPunctuation) {
    // insert the separator
    sentence.insert(" ", at: punctuationIndex)
    // search next punctuation only from the last replacement
    range = sentence.index(after: punctuationIndex)...
}

Однако на самом деле уже существует метод замены String:

sentence = sentence.replacingOccurrences(of: ".", with: " .")

Или дажепроще, с регулярным выражением, охватывающим все знаки препинания за один раз:

return self
    .replacingOccurrences(of: "[,.]", with: " $0", options: .regularExpression)
    .components(separatedBy: " ")
0 голосов
/ 01 февраля 2019

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

import NaturalLanguage

let text = "I am trying to create an array from a sentence. But I don't understand, Why isn't the last fullstop removed, from the last word."

var words: [String] = []

let tagger = NLTagger(tagSchemes: [.lexicalClass])
tagger.string = text
let options: NLTagger.Options = [.omitWhitespace, .joinContractions]
tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .lexicalClass, options: options) { tag, range in
    if let tag = tag {
        words.append(String(text[range]))
    }
    return true
}
print(words)

["I", "am", "пытаюсь", "to", "создать", "an", "array", "from", "a","предложение", ".", "но", "я", "не \", "не понимаю", ",", "почему", "не так", "the", "последний","fullstop", "удален", ",", "из", "the", "last", "word", "."]

Что интересно, это то, что tag свойство расскажет вам части речи, что такое терминатор предложения и т. д., например:

tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .lexicalClass, options: options) { tag, range in
    if let tag = tag {
        print(text[range], tag.rawValue)
    }
    return true
}

Производство:

I Местоимениея глаголпытаясь глаголЧастицамсоздать глаголопределительмассив Nounиз предлогаОпределительпредложение существительное,SentenceTerminatorНо соединениеЯ местоимениене глаголпонять глаголПунктуацияПочему местоимениене глаголОпределительпоследнее прилагательноесуществительное fullstopудаленный глаголПунктуацияиз предлогаОпределительпоследнее прилагательноеслово существительное,SentenceTerminator

Или, может быть, вы действительно не заботитесь о пунктуации и просто хотите разбить ее на предложения и предложения на слова:

var sentences: [[String]] = []

let sentenceTokenizer = NLTokenizer(unit: .sentence)
sentenceTokenizer.string = text

sentenceTokenizer.enumerateTokens(in: text.startIndex ..< text.endIndex) { range, _ in
    let sentence = String(text[range])
    let wordTokenizer = NLTokenizer(unit: .word)
    wordTokenizer.string = sentence

    let words = wordTokenizer.tokens(for: sentence.startIndex ..< sentence.endIndex)
        .map { String(sentence[$0]) }

    sentences.append(words)
    return true
}
print(sentences)

[[«Я», «Я», «пытаясь», «к», «создать», «an», «массив», «из», «а», «предложение»],[«Но», «я», «не понимаю», «понимаю», «почему», «не является», «то», «последний», «полный ход», «удален», «из», "последнее слово"]]

Здесь есть множество опций от NLTagger до NLTokenizer.В зависимости от того, какую проблему вы действительно пытаетесь решить, это может быть лучше, чем манипулирование строками самостоятельно.


Как сказал Султан, вы, очевидно, можете просто вставить пробелы и split строку, хотя яможет предложить добавить другие символы пунктуации и включить + для соответствия нескольким или одному символу в случае последовательных знаков пунктуации (особенно эллипсов, ...), например

let words = text.replacingOccurrences(of: "[,.:;!?]+", with: " $0", options: .regularExpression)
    .split(separator: " ")
0 голосов
/ 31 января 2019

Может быть, вы хотите так:

 func convertSentenceToArray()-> [String] {
    var sentence = String(self)
 sentence =    sentence.replacingOccurrences(of: ".", with: " .")
 sentence =    sentence.replacingOccurrences(of: ",", with: " ,")
    return sentence.components(separatedBy: " ")
}
...