String.substringWithRange를 어떻게 사용합니까? (또는 Swift에서 Ranges는 어떻게 작동합니까?)


266

아직 StringSwift에서 하위 문자열을 얻는 방법을 알 수 없었습니다 .

var str =Hello, playground”
func test(str: String) -> String {
 return str.substringWithRange( /* What goes here? */ )
}
test (str)

Swift에서 범위를 만들 수 없습니다. 놀이터에서 자동 완성 기능은 그다지 도움이되지 않습니다. 이것이 제안하는 것입니다.

return str.substringWithRange(aRange: Range<String.Index>)

Swift Standard Reference Library에서 도움이되는 내용을 찾지 못했습니다. 또 다른 추측은 다음과 같습니다.

return str.substringWithRange(Range(0, 1))

이:

let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)

다른 답변 ( Swift String에서 문자 색인 찾기 )이에 String대한 브리지 유형 NSString이므로 "오래된"메서드가 작동해야하지만 어떻게 작동하는지 명확하지 않습니다. 유효한 구문이 아닌 것 같습니다) :

let x = str.substringWithRange(NSMakeRange(0, 3))

생각?


마지막 예가 효과가 없다고 말할 때 무엇을 의미합니까? 오류가 발생하거나 예기치 않은 값을 반환합니까?
67cherries

첨자 표기법을 요청하는 rdar : // 17158813를 삭제하십시오 openradar.appspot.com/radar?id=6373877630369792
Rob Napier

답변:


259

substringWithRange 메소드를 사용할 수 있습니다. 시작 및 종료 String.Index가 필요합니다.

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"

시작 및 종료 색인을 변경하려면 advancedBy (n)을 사용하십시오.

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"

NSRange와 함께 NSString 메서드를 계속 사용할 수도 있지만 다음과 같이 NSString을 사용하고 있는지 확인해야합니다.

let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))

참고 : JanX2에서 언급 했듯이이 두 번째 방법은 유니 코드 문자열로 안전하지 않습니다.


5
네. 지금은 필요할 때 NSString에 계속 연결합니다. 스위프트의 끈이 여전히 불완전한 것 같습니다
Connor

14
이것은 안전하지 않습니다! String과 NSString에 대한 인덱스를 서로 바꿔 사용할 수 있다고 가정합니다. 그렇지 않습니다. 문자열로의 인덱스는 유니 코드 코드 포인트를 나타내며 NSString으로의 인덱스는 UTF-16 코드 단위를 나타냅니다! 이모티콘으로 사용해보십시오.
JanX2

3
문자열에 대한 인덱스는 더 이상 유니 코드 코드 포인트를 참조하지 않습니다. 그것들을 사용자 인식 문자를 참조하는 것으로 생각하십시오.
JanX2

2
그렇다면 정답은 무엇입니까? 호출 advance은 가능한 긴 문자열을 통해 전체를 반복해야 함을 의미합니다. 그러나 NSRange를 형성하고 명시 적으로 NSString을 사용하는 것은 위험합니까? 무엇이 남았습니까?
matt

1
고마워, m8 Swift 로의 전환은 Objective-C 만 4 년 만에 어지럽습니다.
Felipe

162

스위프트 2

단순한

let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"

스위프트 3

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)

str[startIndex...endIndex]       // "Strin"
str.substring(to: startIndex)    // "My "
str.substring(from: startIndex)  // "String"

스위프트 4

substring(to:)substring(from:)에서 사용되지 않습니다 Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"

2
이. 따라서 사용하기 전에 색인을 찾아야한다고 혼동합니다. 왜 그렇게 오래 걸 렸는지 알지 못했지만 인간의 종류에 기여해 주셔서 감사합니다.
Warpzit

1
신속한 4 하위 문자열 작업에서 문자열 대신 하위 문자열 유형의 인스턴스를 반환합니다. 장기 저장을 위해 결과를 문자열로 변환해야합니다. let newString = String (substring)
phnmnn에서 31:17

43

참고 : @airspeedswift는 이 접근 방식의 절충점, 특히 숨겨진 성능 영향에 대해 매우 통찰력있는 부분 을 만듭니다 . 문자열은 단순한 짐승이 아니며 특정 색인에 도달하는 데 O (n) 시간이 걸릴 수 있습니다. 즉, 아래 첨자를 사용하는 루프는 O (n ^ 2) 일 수 있습니다. 경고를 받았습니다.

subscript범위를 취하고 advancedBy()원하는 곳으로 걸어가 는 데 사용 되는 새로운 기능 을 추가하면 됩니다 .

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(이것은 언어의 일부가되어야합니다. rdar : // 17158813를 삭제하십시오 )

재미있게 +색인에 연산자를 추가 할 수도 있습니다 .

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(이 언어가 언어의 일부인지 여부는 아직 모르겠습니다.)


2
성능상의 이유로 가능한 한 정수 인덱스 대신 String.Index로 작업해야 할 것입니다. 정수 인덱스에서 String.Index로 변환 할 때마다 검색 할 문자열을 처리해야합니다.
JanX2

11
@AndrewDunn 이것은 조기 최적화가 아닙니다. 정수 인덱스에서 문자열로의 각 변환은 O (1)이 아니라 O (n)입니다! 네임 스페이스 advance<T>(…)에서 주석을 읽으십시오 Swift.
JanX2

1
전체 String 구현은을 사용하여 수행됩니다 String.Index. 이 경우 모든 것을 간단하게 유지하는 것만 큼 최적화되지는 않습니다. 어디에서나 int와 String.Index를 번갈아 가면서 엉망으로 만듭니다.
chakrit

@chakrit 사용해야 할 인덱스가 String.Indexes 가 아닌 정수가 아닌 경우에만 해당됩니다 . 모든 문자열 처리 방법이 Ints 로 작동하기를 바랍니다 . 그리고 당신은 String.Indexes당신이 언급 한 혼란에 이르게 수렴해야합니다 .
Rasto

관심있는 독자는 ExSwift 살펴 주어야한다 github.com/pNre/ExSwift을
애 스터

42

필자가 작성하는 당시에는 확장 기능이 Swift 4.2 와 완벽하게 호환되지 않으므로 여기에 내가 생각할 수있는 모든 요구를 충족시키는 확장 기능이 있습니다.

extension String {
    func substring(from: Int?, to: Int?) -> String {
        if let start = from {
            guard start < self.count else {
                return ""
            }
        }

        if let end = to {
            guard end >= 0 else {
                return ""
            }
        }

        if let start = from, let end = to {
            guard end - start >= 0 else {
                return ""
            }
        }

        let startIndex: String.Index
        if let start = from, start >= 0 {
            startIndex = self.index(self.startIndex, offsetBy: start)
        } else {
            startIndex = self.startIndex
        }

        let endIndex: String.Index
        if let end = to, end >= 0, end < self.count {
            endIndex = self.index(self.startIndex, offsetBy: end + 1)
        } else {
            endIndex = self.endIndex
        }

        return String(self[startIndex ..< endIndex])
    }

    func substring(from: Int) -> String {
        return self.substring(from: from, to: nil)
    }

    func substring(to: Int) -> String {
        return self.substring(from: nil, to: to)
    }

    func substring(from: Int?, length: Int) -> String {
        guard length > 0 else {
            return ""
        }

        let end: Int
        if let start = from, start > 0 {
            end = start + length - 1
        } else {
            end = length - 1
        }

        return self.substring(from: from, to: end)
    }

    func substring(length: Int, to: Int?) -> String {
        guard let end = to, end > 0, length > 0 else {
            return ""
        }

        let start: Int
        if let end = to, end - length > 0 {
            start = end - length + 1
        } else {
            start = 0
        }

        return self.substring(from: start, to: to)
    }
}

그런 다음 다음을 사용할 수 있습니다.

let string = "Hello,World!"

string.substring(from: 1, to: 7)당신을 얻는다 : ello,Wo

string.substring(to: 7)당신을 얻는다 : Hello,Wo

string.substring(from: 3)당신을 얻는다 : lo,World!

string.substring(from: 1, length: 4)당신을 얻는다 : ello

string.substring(length: 4, to: 7)당신을 얻는다 : o,Wo

substring(from: Int?, length: Int)0부터 시작하도록 업데이트 되었습니다.


이것은 이모 지와 확장 된 grapheme 클러스터를 어떻게 처리합니까? (내가 직접 테스트해야하지만 현재는 편리하지 않습니다.)
Suragch

2
@Suragch 그것은 잘 처리 : "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)우리에게 제공 :o😇😍😘😎📸📀💾∝ℵℶ
winterized

그래도 일반 캐릭터처럼 보입니다. 👩‍👩‍👧‍👦 또는 🇨🇦🇺🇸🇲🇽
Supuhstar

31

스위프트 2.0

단순한:

let myString = "full text container"
let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful

스위프트 3.0

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

스위프트 4.0

부분 문자열 연산은 문자열 대신 부분 문자열 유형의 인스턴스를 반환합니다.

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

// Convert the result to a String for long-term storage.
let newString = String(substring)

4
슬프게도 Xcode 8 베타 6부터 Swift 3과 더 이상 호환되지 않음
Ben Morrow

1
나를 위해 작동합니다. Xcode 8, Swift 3. Mac OS Sierra에서는 베타 버전이 아닙니다. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jose Ramirez

18

올바른 구문을 찾으면 여기에있는 답변보다 훨씬 간단합니다.

[및]를 제거하고 싶습니다

let myString = "[ABCDEFGHI]"
let startIndex = advance(myString.startIndex, 1) //advance as much as you like
let endIndex = advance(myString.endIndex, -1)
let range = startIndex..<endIndex
let myNewString = myString.substringWithRange( range )

결과는 "ABCDEFGHI"입니다. startIndex 및 endIndex도 사용할 수 있습니다.

let mySubString = myString.substringFromIndex(startIndex)

등등!

추신 : 비고에서 알 수 있듯이, swift 2에는 xcode 7 및 iOS9와 함께 제공되는 구문 변경이 있습니다!

페이지를 봐주세요


예, 디버거와 동일한 문제가 여러 번 올바른 문자열을 표시하지 않습니까?
user1700737

이 / Date (147410000000) /와 같은 문자열이 있습니다. 색인을 지정하는 대신 어떻게 가치를 얻을 수 있습니까? rangeOfString ( "(") 및 rangeOfString ( ")")을 사용하여 값을 가져와야합니다. 결과는 147410000000이되어야합니다. Hoe 그것을 얻을 수 있습니다
iPhone Guy

그렇게 어렵지는 않습니다 : var str = "/ Date (147410000000) /." var range = str.rangeOfString ( "(") !. endIndex .. <str.rangeOfString ( ")") !. startIndex let myNewString = str.substringWithRange (range)
user1700737

4
Xcode 7 베타 6 advance(myString.endIndex, -1)구문이myString.endIndex.advancedBy(-1)
l --marc l로

16

예를 들어 내 이름에서 이름을 찾으려면 (첫 번째 공백까지) :

let name = "Joris Kluivers"

let start = name.startIndex
let end = find(name, " ")

if end {
    let firstName = name[start..end!]
} else {
    // no space found
}

start그리고 여기 end에 유형 이 있고 아래 첨자 접근 자에서 사용하고 사용합니다 (원래 문자열에 공백이있는 경우).String.IndexRange<String.Index>

String.Index오프닝 포스트에서 사용되는 정수 위치에서 직접 생성하기는 어렵 습니다. 이것은 내 이름에서 각 문자의 크기가 바이트 단위이기 때문입니다. 그러나 다른 언어에서 특수 억양을 사용하는 문자는 사용 된 인코딩에 따라 몇 바이트를 더 사용할 수 있습니다. 정수는 어떤 바이트를 참조해야합니까?

그것은 새로운을 만들 수의 String.Index방법을 사용하여 기존의 하나 succpred반드시 정확한 바이트 수는 인코딩에서 다음 코드 포인트에 도착 건너 뜁니다 할 것이다. 그러나이 경우 문자열에서 첫 번째 공백의 색인을 검색하여 종료 색인을 찾는 것이 더 쉽습니다.


16

String은 NSString의 브리지 유형이므로 "이전"메소드는 작동해야하지만 방법이 명확하지 않습니다. 예를 들어, 이것이 작동하지 않습니다 (유효한 구문으로 보이지 않음).

 let x = str.substringWithRange(NSMakeRange(0, 3))

나에게, 그것은 당신의 질문에서 정말로 흥미로운 부분입니다. 문자열 NSString에 브리지되므로 대부분의 NSString 메서드 문자열에서 직접 작동합니다. 생각없이 자유롭게 사용할 수 있습니다. 예를 들어, 이것은 예상대로 작동합니다.

// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")

그러나 종종 발생하는 것처럼 "저는 모조가 작동하고 있지만 작동하지 않습니다." 동일한 이름의 병렬 Swift 메소드가 존재 하는 드문 경우 중 하나를 선택 했으며, 이와 같은 경우 Swift 메소드는 Objective-C 메소드를 어둡게합니다. 따라서 str.substringWithRangeSwift는 NSString 메서드가 아닌 Swift 메서드를 의미한다고 생각합니다. 그러면 Swift 메서드가을 기대하고 Range<String.Index>그 중 하나를 만드는 방법을 모르기 때문에 호스가 있습니다.

쉬운 방법은 Swift가 다음과 같이 명시 적으로 캐스팅하여 그림자가 생기는 것을 막는 것입니다.

let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))

여기에는 중요한 추가 작업이 필요하지 않습니다. "Cast"는 "변환"을 의미하지 않습니다. 문자열 사실상 NSString입니다. 우리는 이 한 줄의 코드를 위해 Swift 에게이 변수 를 보는 방법을 알려줍니다 .

이 모든 것의 정말로 이상한 부분은이 모든 문제를 일으키는 Swift 방법이 문서화되지 않았다는 것입니다. 나는 그것이 어디에 정의되어 있는지 모른다. NSString 헤더에 없으며 Swift 헤더에도 없습니다.


그러나 버그 신고를 제안합니다. 애플은 "낚시 또는 미끼를 잘라 내야한다"-우리에게을 구성 할 수있는 방법을 제공 Range<String.Index>하거나 문서화되지 않은 방법을 우리의 길에서 벗어나게해야한다.
matt

젠장-이것은 유용합니다. 문서의 내용에도 불구하고, 나는 이것을 읽을 때까지 무엇이 잘못되었는지 이해하지 못했습니다. Now Sort :)
Jon M

13

새로운 Xcode 7.0에서는

//: Playground - noun: a place where people can play

import UIKit

var name = "How do you use String.substringWithRange?"
let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10)
name.substringWithRange(range)

//OUT:

여기에 이미지 설명을 입력하십시오


2
.advancedBy(0) startIndex에는 필요하지 않습니다.
Mat0

12

짧은 대답은 현재 스위프트에서는 이것이 어렵다는 것입니다. 필자의 직감은 애플이 이와 같은 편리한 방법에 대해 아직도해야 할 일이 많다는 것이다.

String.substringWithRange()Range<String.Index>매개 변수를 기대하고 있으며 String.Index유형에 대한 생성기 메서드가 없다는 것을 알 수 있습니다 . 당신이 얻을 수있는 String.Index값에서 백업 aString.startIndexaString.endIndex및 전화 .succ()또는 .pred()그들 만의 광기있다.

좋은 Ints 를 취하는 String 클래스의 확장은 어떻습니까?

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let subStart = advance(self.startIndex, r.startIndex, self.endIndex)
            let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex)
            return self.substringWithRange(Range(start: subStart, end: subEnd))
        }
    }
    func substring(from: Int) -> String {
        let end = countElements(self)
        return self[from..<end]
    }
    func substring(from: Int, length: Int) -> String {
        let end = from + length
        return self[from..<end]
    }
}

let mobyDick = "Call me Ishmael."
println(mobyDick[8...14])             // Ishmael

let dogString = "This 🐶's name is Patch."
println(dogString[5..<6])               // 🐶
println(dogString[5...5])              // 🐶
println(dogString.substring(5))        // 🐶's name is Patch.
println(dogString.substring(5, length: 1))   // 🐶

업데이트 : Swift beta 4는 아래 문제를 해결합니다!

베타 3 이하 버전에서는 Swift 네이티브 문자열조차도 유니 코드 문자를 처리하는 데 몇 가지 문제가 있습니다. 위의 개 아이콘은 작동했지만 다음과 같이 작동하지 않습니다.

let harderString = "1:1️⃣"
for character in harderString {
    println(character)
}

산출:

1
:
1
️
⃣

1
이상한 Swift 클래스에는 많은 기본 기능이 부족한 것 같습니다. Apple이 Foundation 클래스를 지속적으로 참조하여 간단한 작업을 수행하기를 원한다고 생각할 수 없습니다.
bluedevil2k

1
전적으로. Swift는 기본적으로 어둠 속에서 개발되었으며 모든 사람들이 "간단한 작업"에 대해 다른 정의를 가지고 있음을 명심하십시오. 이러한 문제에 대해 약간의 반복이있을 것입니다.
Nate Cook

@ JanX2-고마워, 당신 말이 맞아. 원활한 브리징을 NSString통해 전화를 String사용하지 않았기 때문에 스위프트 네이티브 방식 만 사용하고 있다고 생각했습니다 myString as NSString.
Nate Cook

스위프트 네이티브 문자열 처리에는 현재 유니 코드 버그가 있습니다. 마지막 노트를 참조하십시오.
Nate Cook

@NateCook 해당 문제에 대한 레이더를 제출할 수 있습니까?
JanX2

11

이 확장을 사용하여 개선 할 수 있습니다 substringWithRange

스위프트 2.3

extension String
{   
    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(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 str = "Hello, playground"

let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground

7

Swift 2.0 에서 부분 문자열을 얻는 방법에 대한 샘플 코드

(i) 시작 색인의 하위 문자열

입력:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)

산출:-

Swift is very powerful language!
Swift

(ii) 특정 색인의 하위 문자열

입력:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)

산출:-

Swift is very powerful language!
is

도움이 되길 바랍니다.


7

적은 코드로 쉬운 솔루션.

거의 모든 다른 언어에서 사용되는 기본 하위 문자열을 포함하는 확장을 만드십시오.

extension String {
    func subString(start: Int, end: Int) -> String {
        let startIndex = self.index(self.startIndex, offsetBy: start)
        let endIndex = self.index(startIndex, offsetBy: end)

        let finalString = self.substring(from: startIndex)
        return finalString.substring(to: endIndex)
    }
}

간단히 전화하세요

someString.subString(start: 0, end: 6)

1
'end'매개 변수는 실제로 길이를 의미하므로 이름을 바꿔야한다고 생각합니다.
Jovan Jovanovski

길이를 사용하는 것이 다소 혼란 스럽다고 생각합니다. 실제로 subStrings 결과의 실제 길이가 아니라 subString을 원하는 위치의 '종료'입니다.
Oliver Dixon

6

이것은 내 놀이터에서 작동합니다 :)

String(seq: Array(str)[2...4])

실제로 이것은 전화하는 것보다 더 효율적입니다advance
Erik Aigner

2
내 Xcode 7 (Swift 2) 놀이터에서 작동하지 않지만 다음과 같습니다 ... 'var str = "Hello, playground"'String (Array (str.characters) [7]) // "p"String (Array ( str.characters) [7 ... 10]) // "play"String (Array (str.characters) [7 .. <10]) // "pla"
Vince O'Sullivan

6

Xcode 7 용으로 업데이트되었습니다. 문자열 확장을 추가합니다.

사용하다:

var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck

이행:

extension String {

    /**
     Subscript to allow for quick String substrings ["Hello"][0...1] = "He"
     */
    subscript (r: Range<Int>) -> String {
        get {
            let start = self.startIndex.advancedBy(r.startIndex)
            let end = self.startIndex.advancedBy(r.endIndex - 1)
            return self.substringWithRange(start..<end)
        }
    }

}

4

운동장에서 이것을 시도

var str:String = "Hello, playground"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))

"ello, p"를 줄 것이다

그러나 이것이 실제로 흥미로운 곳은 놀이터의 문자열보다 마지막 색인을 크게하면 str 다음에 정의한 모든 문자열을 표시한다는 것입니다.

Range ()는 일반 함수처럼 보이므로 처리하는 형식을 알아야합니다.

또한 놀이터에 관심있는 실제 줄을 제공해야합니다. 따라서 나중에 변수 이름을 사용하여 모든 찌르기를 차례로 순서대로 유지하는 것처럼 보입니다.

그래서

var str:String = "Hello, playground"

var str2:String = "I'm the next string"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49))

제공 "여보세요, playgroundstrI'm 다음 stringstr2"

str2가 let으로 정의 된 경우에도 작동

:)


Objective-C에 비해 장황하다는 데 동의하지만 모두 한 줄에 맞는 보너스입니다.
피터 로버츠

글쎄, 여전히 계산 한 범위에 따라 부분 문자열을 인쇄하는 한 줄이 누락되었습니다. 나는 당신의 논리를 사용하여 String 클래스 확장을 만드는 다른 솔루션 중 일부를 좋아하지만 확장입니다. 그것이 궁극적으로 내가 함께했던 해결책입니다.
Roderic Campbell

그들은 문자열의 끝을 넘어 갈 수있는 버그를 수정했습니다. 이제 str.endIndex까지만 값을 입력 할 수 있습니다
Peter Roberts

4

롭 네이피어는 이미 아래 첨자를 사용하여 멋진 대답을했습니다. 그러나 바운드 조건을 점검하지 않기 때문에 한 가지 단점을 느꼈습니다. 충돌하는 경향이 있습니다. 그래서 나는 확장을 수정했고 여기에 있습니다.

extension String {
    subscript (r: Range<Int>) -> String? { //Optional String as return value
        get {
            let stringCount = self.characters.count as Int
            //Check for out of boundary condition
            if (stringCount < r.endIndex) || (stringCount < r.startIndex){
                return nil
            }
            let startIndex = self.startIndex.advancedBy(r.startIndex)

            let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

아래 출력

var str2 = "Hello, World"

var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil

그래서 나는 항상 if let을 확인하는 것이 좋습니다.

if let string = str[0...5]
{
    //Manipulate your string safely
}

버그가 있습니다-endIndex는 인덱스 사이의 거리가 아닌 endIndex만으로 startIndex 고급이어야합니다.
Aviad 벤 도브

3

에서 Swift3

예 : 변수 "Duke James Thomas"의 경우 "James"를 가져와야합니다.

let name = "Duke James Thomas"
let range: Range<String.Index> = name.range(of:"James")!
let lastrange: Range<String.Index> = img.range(of:"Thomas")!
var middlename = name[range.lowerBound..<lstrange.lowerBound]
print (middlename)

2

Rob Napier에서 페이지를 가져 와서이 공통 문자열 확장을 개발했습니다 . 그 중 두 가지는 다음과 같습니다.

subscript (r: Range<Int>) -> String
{
    get {
        let startIndex = advance(self.startIndex, r.startIndex)
        let endIndex = advance(self.startIndex, r.endIndex - 1)

        return self[Range(start: startIndex, end: endIndex)]
    }
}

func subString(startIndex: Int, length: Int) -> String
{
    var start = advance(self.startIndex, startIndex)
    var end = advance(self.startIndex, startIndex + length)
    return self.substringWithRange(Range<String.Index>(start: start, end: end))
}

용법:

"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"

형식 유추 덕분에 Range대신 사용할 수 있습니다 Range<String.Index>.
Dan Rosenstark

2

이것은 문자열에서 범위를 얻는 방법입니다.

var str = "Hello, playground"

let startIndex = advance(str.startIndex, 1)
let endIndex = advance(startIndex, 8)
let range = startIndex..<endIndex
let substr = str[range] //"ello, pl"

핵심은 정수 대신 String.Index 유형의 값 범위를 전달한다는 것입니다.

이것이 필요한 이유는 기본적으로 가변 길이의 유니 코드 문자 때문에 Swift의 문자열에 임의 액세스 권한이 없기 때문입니다. 당신은 또한 할 수 없습니다str[1] . String.Index는 내부 구조와 작동하도록 설계되었습니다.

그래도 아래 첨자를 사용하여 확장을 만들 수 있으므로이를 수행하면 다양한 정수를 전달할 수 있습니다 (예 : Rob Napier의 답변 참조 ).


2

나는 파이썬 같은 것을 생각해 보았습니다.

여기의 모든 아래 첨자는 훌륭하지만, 실제로 간단한 것이 필요한 시간은 일반적으로 다시 계산하고 싶을 때입니다. string.endIndex.advancedBy(-1)

nil시작 및 종료 색인 모두에 대한 값을 지원 합니다. 여기서 nil시작의 경우 0의 색인을 의미 string.characters.count합니다.

extension String {
    var subString: (Int?) -> (Int?) -> String {
        return { (start) in
            { (end) in
                let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
                let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)

                return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
            }
        }
    }
}

let dog = "Dog‼🐶"
print(dog.subString(nil)(-1)) // Dog!!

편집하다

보다 우아한 솔루션 :

public extension String {
    struct Substring {
        var start: Int?
        var string: String

        public subscript(end: Int?) -> String {
            let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0)
            let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count)

            return startIndex > endIndex ? "" : string.substringWithRange(startIndex ..< endIndex)
        }
    }

    public subscript(start: Int?) -> Substring {
        return Substring(start: start, string: self)
    }
}

let dog = "Dog‼🐶"
print(dog[nil][-1]) // Dog!!

1

먼저 범위를 만든 다음 하위 문자열을 만듭니다. 다음 fromIndex..<toIndex과 같은 구문 을 사용할 수 있습니다 .

let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)

1

다음은 전체 URL에서 비디오 ID 만 .ie (6oL687G0Iso) 를 신속하게 얻는 예입니다.

let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)



0

글쎄, 나는 같은 문제가 있었고 "bridgeToObjectiveC ()"함수로 해결했다.

var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!

이 예에서 substringWithRange는 NSMakeRange와 함께 인덱스 6 (문자 "W")에서 시작하여 인덱스 6 + 6 위치에서 끝나는 문자열 (문자 "!")의 일부를 취합니다.

건배.


나는 이것을 싫어하지만 베타 4에서 나를 위해 작동하는 유일한 것입니다.
Roderic Campbell


0

이 있으면 NSRange브리징이 NSString원활하게 작동합니다. 예를 들어, 나는 약간의 작업을 UITextFieldDelegate하고 있었고 범위를 바꿀 것인지 물었을 때 새 문자열 값을 신속하게 계산하려고했습니다.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    println("Got new string: ", newString)
}

0

간단한 확장 을 위해 String:

extension String {

    func substringToIndex(index: Int) -> String {
        return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
    }
}

0

성능에 관심이 없다면 Swift 4에서 가장 간결한 솔루션 일 것입니다.

extension String {
    subscript(range: CountableClosedRange<Int>) -> String {
        return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
            .reduce(""){$0 + String($1.element)}
    }
}

다음과 같은 작업을 수행 할 수 있습니다.

let myStr = "abcd"
myStr[0..<2] // produces "ab"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.