Решение, которое сохраняет пробелы и пунктуацию без изменений.
Мы найдем их с помощью метода расширения indiciesOfPuntationBlanks() -> [Int]
.замена случайно выбранных символов будет сделана на blankOut(percentage: Double) -> String
extension String {
func indiciesOfPuntationBlanks() -> [Int] {
let charSet = CharacterSet.punctuationCharacters.union(.whitespaces)
var indices = [Int]()
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.rangeOfCharacter(from: charSet, options: [], range: searchStartIndex ..< self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
func blankOut(percentage: Double) -> String {
var result = self
let blankIndicies = result.indiciesOfPuntationBlanks()
let allNonBlankIndicies = Set(0 ..< result.count).subtracting(blankIndicies).shuffled()
let picked = allNonBlankIndicies.prefix(Int(Double(allNonBlankIndicies.count) * percentage))
picked.forEach { (idx) in
let start = result.index(result.startIndex, offsetBy: idx);
let end = result.index(result.startIndex, offsetBy: idx + 1);
result.replaceSubrange(start ..< end, with: "_")
}
return result
}
}
Использование:
let str = "Hello, World!"
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75))
}
Вывод:
____o, _or__!
_e___, __rl_!
_e__o, __r__!
H____, W_r__!
H_l__, W____!
_____, _or_d!
_e_lo, _____!
_____, _orl_!
_____, _or_d!
___l_, W___d!
То же решение, но можно настроить строку для пропуска и игнорируемые наборы символов
extension String {
func indicies(with charSets:[CharacterSet]) -> [Int] {
var indices = [Int]()
let combinedCahrSet: CharacterSet = charSets.reduce(.init()) { $0.union($1) }
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.rangeOfCharacter(from: combinedCahrSet, options: [], range: searchStartIndex ..< self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
func blankOut(percentage: Double, with blankOutString: String = "_", ignore charSets: [CharacterSet] = [.punctuationCharacters, .whitespaces]) -> String {
var result = self
let blankIndicies = result.indicies(with: charSets)
let allNonBlankIndicies = Set(0 ..< result.count).subtracting(blankIndicies).shuffled()
let picked = allNonBlankIndicies.prefix(Int(Double(allNonBlankIndicies.count) * percentage))
picked.forEach { (idx) in
let start = result.index(result.startIndex, offsetBy: idx);
let end = result.index(result.startIndex, offsetBy: idx + 1);
result.replaceSubrange(start ..< end, with: blankOutString)
}
return result
}
}
Использование:
let str = "Hello, World!"
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75))
}
print("--------------------")
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75, with:"x", ignore: [.punctuationCharacters]))
}
print("--------------------")
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75, with:"*", ignore: []))
}
Вывод:
_el_o, _____!
__llo, _____!
He__o, _____!
_e___, W_r__!
_el_o, _____!
_el__, ___l_!
_e___, __rl_!
_e__o, _o___!
H____, Wo___!
H____, __rl_!
--------------------
xxxlx,xWxrxx!
xxxxx,xxorxd!
Hxxxx,xWxrxx!
xxxxx, xoxlx!
Hxllx,xxxxxx!
xelxx,xxoxxx!
Hxxxx,xWxxxd!
Hxxxo,xxxxxd!
Hxxxx,xxorxx!
Hxxxx, Wxxxx!
--------------------
***l***Wo**d*
*e**o**W**l**
***lo**Wo****
*el*****or***
H****,****ld*
***l*, **r***
*el*o* ******
*e*lo*******!
H*l****W***d*
H****, **r***