문자열을 다른 문자열로 바꾸는 가장 좋은 / 간단한 방법을 배우고 싶지만 하위 집합 만 사용하여 문자의 시작 부분에서 시작하여 마지막 인덱스로 이동합니다.
예를 들어 “www.stackoverflow.com”을 “www.stackoverflow”로 변환합니다. 어떤 코드 스 니펫이이를 수행하고 가장 신속하게 처리 할 수 있습니까? (나는 이것이 논쟁을 불러 일으키지 않기를 바라지 만, Swift에서 부분 문자열을 처리하는 방법에 대한 좋은 교훈을 찾을 수 없습니다.
답변
뒤로 접근
가장 좋은 방법은 속성과 전역 함수를 substringToIndex
결합 하여 사용 endIndex
하는 advance
것입니다.
var string1 = "www.stackoverflow.com"
var index1 = advance(string1.endIndex, -4)
var substring1 = string1.substringToIndex(index1)
뒤에서 시작하는 문자열을 찾고
사용 rangeOfString
및 설정 options
에.BackwardsSearch
var string2 = "www.stackoverflow.com"
var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex
var substring2 = string2.substringToIndex(index2!)
확장 없음, 순수한 관용적 Swift
스위프트 2.0
advance
이제의 일부 Index
이며이라고 advancedBy
합니다. 다음과 같이합니다.
var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
스위프트 3.0
당신은 호출 할 수 없습니다 advancedBy
A의 String
는 가변 크기의 요소를 가지고 있기 때문이다. 을 사용해야 index(_, offsetBy:)
합니다.
var string1 = "www.stackoverflow.com"
var index1 = string1.index(string1.endIndex, offsetBy: -4)
var substring1 = string1.substring(to: index1)
많은 것들이 이름이 바뀌 었습니다. 사건은 낙타 표기법으로 작성되어, startIndex
되었다 lowerBound
.
var string2 = "www.stackoverflow.com"
var index2 = string2.range(of: ".", options: .backwards)?.lowerBound
var substring2 = string2.substring(to: index2!)
또한 force unwrapping을 권장하지 않습니다 index2
. 선택적 바인딩 또는 map
. 개인적으로 다음을 선호합니다 map
.
var substring3 = index2.map(string2.substring(to:))
스위프트 4
Swift 3 버전은 여전히 유효하지만 이제 인덱스 범위와 함께 아래 첨자를 사용할 수 있습니다.
let string1 = "www.stackoverflow.com"
let index1 = string1.index(string1.endIndex, offsetBy: -4)
let substring1 = string1[..<index1]
두 번째 접근 방식은 변경되지 않습니다.
let string2 = "www.stackoverflow.com"
let index2 = string2.range(of: ".", options: .backwards)?.lowerBound
let substring3 = index2.map(string2.substring(to:))
답변
스위프트 3, XCode 8
func lastIndexOfCharacter(_ c: Character) -> Int? {
return range(of: String(c), options: .backwards)?.lowerBound.encodedOffset
}
advancedBy(Int)
Swift 3은 String
‘s method를 사용 하기 때문에 사라졌습니다 index(String.Index, Int)
. String
하위 문자열 및 친구들과 함께이 확장을 확인하십시오 .
public extension String {
//right is the first encountered string after left
func between(_ left: String, _ right: String) -> String? {
guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
, leftRange.upperBound <= rightRange.lowerBound
else { return nil }
let sub = self.substring(from: leftRange.upperBound)
let closestToLeftRange = sub.range(of: right)!
return sub.substring(to: closestToLeftRange.lowerBound)
}
var length: Int {
get {
return self.characters.count
}
}
func substring(to : Int) -> String {
let toIndex = self.index(self.startIndex, offsetBy: to)
return self.substring(to: toIndex)
}
func substring(from : Int) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: from)
return self.substring(from: fromIndex)
}
func substring(_ r: Range<Int>) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
return self.substring(with: Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex)))
}
func character(_ at: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: at)]
}
func lastIndexOfCharacter(_ c: Character) -> Int? {
guard let index = range(of: String(c), options: .backwards)?.lowerBound else
{ return nil }
return distance(from: startIndex, to: index)
}
}
Swift 4의 업데이트 된 확장
public extension String {
//right is the first encountered string after left
func between(_ left: String, _ right: String) -> String? {
guard
let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
, leftRange.upperBound <= rightRange.lowerBound
else { return nil }
let sub = self[leftRange.upperBound...]
let closestToLeftRange = sub.range(of: right)!
return String(sub[..<closestToLeftRange.lowerBound])
}
var length: Int {
get {
return self.count
}
}
func substring(to : Int) -> String {
let toIndex = self.index(self.startIndex, offsetBy: to)
return String(self[...toIndex])
}
func substring(from : Int) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: from)
return String(self[fromIndex...])
}
func substring(_ r: Range<Int>) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
let indexRange = Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))
return String(self[indexRange])
}
func character(_ at: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: at)]
}
func lastIndexOfCharacter(_ c: Character) -> Int? {
guard let index = range(of: String(c), options: .backwards)?.lowerBound else
{ return nil }
return distance(from: startIndex, to: index)
}
}
용법:
let text = "www.stackoverflow.com"
let at = text.character(3) // .
let range = text.substring(0..<3) // www
let from = text.substring(from: 4) // stackoverflow.com
let to = text.substring(to: 16) // www.stackoverflow
let between = text.between(".", ".") // stackoverflow
let substringToLastIndexOfChar = text.lastIndexOfCharacter(".") // 17
추신 : 개발자 String.Index
가 평범한 대신 처리하도록 강요 한 것은 정말 이상합니다 Int
. String
단순한 substring()
방법 이 아닌 내부 역학에 신경을 써야하는 이유는 무엇 입니까?
답변
아래 첨자 ( s[start..<end]
)를 사용하여 수행합니다 .
스위프트 3, 4, 5
let s = "www.stackoverflow.com"
let start = s.startIndex
let end = s.index(s.endIndex, offsetBy: -4)
let substring = s[start..<end] // www.stackoverflow
답변
편집 / 업데이트 :
년 이후 스위프트 4 (엑스 코드 10.0+) 새 사용할 수 있습니다 BidirectionalCollection의
방법 으로 (는 lastIndex를 🙂
func lastIndex(of element: Element) -> Int?
let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
let subString = string[..<lastIndex] // "www.stackoverflow"
}
답변
방법은 다음과 같습니다. 같은 방식으로 할 수도 있고 아이디어를 위해이 코드를 사용할 수도 있습니다.
let s = "www.stackoverflow.com"
s.substringWithRange(0..<s.lastIndexOf("."))
내가 사용하는 확장 프로그램은 다음과 같습니다.
import Foundation
extension String {
var length: Int {
get {
return countElements(self)
}
}
func indexOf(target: String) -> Int {
var range = self.rangeOfString(target)
if let range = range {
return distance(self.startIndex, range.startIndex)
} else {
return -1
}
}
func indexOf(target: String, startIndex: Int) -> Int {
var startRange = advance(self.startIndex, startIndex)
var range = self.rangeOfString(target, options: NSStringCompareOptions.LiteralSearch, range: Range<String.Index>(start: startRange, end: self.endIndex))
if let range = range {
return distance(self.startIndex, range.startIndex)
} else {
return -1
}
}
func lastIndexOf(target: String) -> Int {
var index = -1
var stepIndex = self.indexOf(target)
while stepIndex > -1 {
index = stepIndex
if stepIndex + target.length < self.length {
stepIndex = indexOf(target, startIndex: stepIndex + target.length)
} else {
stepIndex = -1
}
}
return index
}
func substringWithRange(range:Range<Int>) -> String {
let start = advance(self.startIndex, range.startIndex)
let end = advance(self.startIndex, range.endIndex)
return self.substringWithRange(start..<end)
}
}
Credit albertbori / Common Swift String Extensions
일반적으로 저는 특히 문자열 조작, 검색 및 슬라이싱과 같은 요구 사항에 대해 확장을 강력하게지지합니다.
답변
String
내장 하위 문자열 기능이 있습니다.
extension String : Sliceable {
subscript (subRange: Range<String.Index>) -> String { get }
}
원하는 것이 ” 문자 의 첫 번째 인덱스로 이동”하는 것이라면 내장 find()
함수를 사용하여 하위 문자열을 얻을 수 있습니다 .
var str = "www.stackexchange.com"
str[str.startIndex ..< find(str, ".")!] // -> "www"
마지막 인덱스 를 찾으려면 findLast()
.
/// Returns the last index where `value` appears in `domain` or `nil` if
/// `value` is not found.
///
/// Complexity: O(\ `countElements(domain)`\ )
func findLast<C: CollectionType where C.Generator.Element: Equatable>(domain: C, value: C.Generator.Element) -> C.Index? {
var last:C.Index? = nil
for i in domain.startIndex..<domain.endIndex {
if domain[i] == value {
last = i
}
}
return last
}
let str = "www.stackexchange.com"
let substring = map(findLast(str, ".")) { str[str.startIndex ..< $0] } // as String?
// if "." is found, substring has some, otherwise `nil`
추가됨 :
아마도의 BidirectionalIndexType
특수 버전 findLast
이 더 빠를 것입니다.
func findLast<C: CollectionType where C.Generator.Element: Equatable, C.Index: BidirectionalIndexType>(domain: C, value: C.Generator.Element) -> C.Index? {
for i in lazy(domain.startIndex ..< domain.endIndex).reverse() {
if domain[i] == value {
return i
}
}
return nil
}
답변
다음 확장을 사용할 수 있습니다.
스위프트 2.3
extension String
{
func substringFromIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringFromIndex(self.startIndex.advancedBy(index))
}
func substringToIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringToIndex(self.startIndex.advancedBy(index))
}
func substringWithRange(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
return self.substringWithRange(range)
}
func substringWithRange(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
return self.substringWithRange(range)
}
}
스위프트 3
extension String
{
func substring(from index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(from: self.characters.index(self.startIndex, offsetBy: index))
}
func substring(to index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
}
func substring(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: end)
let range = startIndex..<endIndex
return self.substring(with: range)
}
func substring(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
let range = startIndex..<endIndex
return self.substring(with: range)
}
}
용법:
let string = "www.stackoverflow.com"
let substring = string.substringToIndex(string.characters.count-4)