Swift에서 문자열에서 첫 번째 문자를 제거하는 가장 간결한 방법은 무엇입니까?


122

문자열에서 첫 번째 문자를 삭제하고 싶습니다. 지금까지 제가 생각 해낸 가장 간결한 것은 다음과 같습니다.

display.text = display.text!.substringFromIndex(advance(display.text!.startIndex, 1))

Int유니 코드 때문에 문자열로 인덱싱 할 수 없다는 것을 알고 있지만이 솔루션은 매우 장황 해 보입니다. 내가 간과하는 또 다른 방법이 있습니까?


3
실제로 NSString advance으로 캐스팅 하여 모든 것을 피할 수 있습니다 display.text!. 나는 그것이 좋은 해결책이라고 말하는 것이 아닙니다. 단지 가능한 오해를 바로 잡는 것입니다. NSString을 사용하면 Int로 인덱싱 할 수 있습니다 . -Int로 인덱싱 할 수없는 이유는 유니 코드 때문이 아닙니다. 문자가 여러 복합 코드 포인트로 구성 될 수 있기 때문입니다.

대문자를 사용하기 위해이 작업을 수행하면 StringSwift 3 capitalized에서 String.
Vince O'Sullivan

답변:


208

Swift 3을 사용 하는 경우이 답변의 두 번째 섹션을 무시할 수 있습니다. 좋은 소식은 이것이 실제로 다시 간결하다는 것입니다! String의 새로운 remove (at :) 메서드를 사용하기 만하면됩니다.

var myString = "Hello, World"
myString.remove(at: myString.startIndex)

myString // "ello, World"

나는 dropFirst()이것에 대한 전역 함수를 좋아합니다 .

let original = "Hello" // Hello
let sliced = dropFirst(original) // ello

짧고 명확하며 Sliceable 프로토콜을 준수하는 모든 것에 대해 작동합니다.

Swift 2 를 사용하는 경우이 답변이 변경되었습니다. dropFirst는 여전히 사용할 수 있지만 strings characters속성 에서 첫 번째 문자를 삭제 한 다음 결과를 다시 String으로 변환 하지 않으면 사용할 수 없습니다 . dropFirst는 또한 함수가 아닌 메소드가되었습니다.

let original = "Hello" // Hello
let sliced = String(original.characters.dropFirst()) // ello

또 다른 대안은 접미사 기능을 사용하여 문자열의 UTF16View. 물론 나중에 다시 문자열로 변환해야합니다.

let original = "Hello" // Hello
let sliced = String(suffix(original.utf16, original.utf16.count - 1)) // ello

이 모든 것은 내가 원래 제공 한 솔루션이 최신 버전의 Swift에서이 작업을 수행하는 가장 간결한 방법이 아니라는 것입니다. removeAtIndex()짧고 직관적 인 솔루션을 찾고 있다면 @chris의 솔루션을 사용 하는 것이 좋습니다 .

var original = "Hello" // Hello
let removedChar = original.removeAtIndex(original.startIndex)

original // ello

아래 주석에서 @vacawama가 지적했듯이 원래 문자열을 수정하지 않는 또 다른 옵션은 substringFromIndex를 사용하는 것입니다.

let original = "Hello" // Hello
let substring = original.substringFromIndex(advance(original.startIndex, 1)) // ello

또는 문자열의 시작과 끝에서 문자를 드롭하려는 경우 substringWithRange를 사용할 수 있습니다. 때 상태에 대해 조심하십시오 startIndex + n > endIndex - m.

let original = "Hello" // Hello

let newStartIndex = advance(original.startIndex, 1)
let newEndIndex = advance(original.endIndex, -1)

let substring = original.substringWithRange(newStartIndex..<newEndIndex) // ell

마지막 줄은 아래 첨자 표기법을 사용하여 작성할 수도 있습니다.

let substring = original[newStartIndex..<newEndIndex]

2
그리고 재단 세계에 발을 들여 놓을 필요도 없습니다.

2
그리고 그것은 매우 신속 / fp입니다.
David Berry

감사합니다. 훨씬 더 우아합니다. 저는 Objective C에서 수년간 프로그래밍을 해왔으며 Swift에서 iTunes U Stanford iOS 프로그래밍 과정을 수강하고 있습니다. 나는 여전히 새로운 패러다임에 대해 배울 것이 많다.
SSteve

1
dropLast 또는 dropFirst를 사용하는 동안 염두에 두십시오. 그렇지 않으면 작동하지 않습니다.
Bhavuk Jain

3
좋은 대답입니다! remove(at:)메서드 의 반환 값에 주목할 가치가 있다고 생각 합니다. 새 문자열이 아니라 제거 된 문자입니다. 예를 들면 let removedCharacter = myString.remove(at: myString.startIndex). 메서드 호출의 결과를 반환하는 실수를 저질렀습니다. 이것이이 접근 방식의 경우라는 것을 잊었습니다. 모두 즐겁게 코딩하세요!
kbpontius

118

Swift 4 업데이트

Swift 4에서는 다시 String준수 Collection하므로 문자열의 시작과 끝 을 사용 dropFirst하고 dropLast트리밍 할 수 있습니다. 결과는 유형 Substring이므로 String생성자에 전달하여 다음 을 반환해야합니다 String.

let str = "hello"
let result1 = String(str.dropFirst())    // "ello"
let result2 = String(str.dropLast())     // "hell"

dropFirst()그리고 dropLast()또한을 Int드롭 문자의 수를 지정합니다 :

let result3 = String(str.dropLast(3))    // "he"
let result4 = String(str.dropFirst(4))   // "o"

삭제할 문자를 문자열에있는 것보다 더 많이 지정하면 결과는 빈 문자열 ( "")이됩니다.

let result5 = String(str.dropFirst(10))  // ""

Swift 3 업데이트

첫 번째 문자를 제거하고 원래 문자열을 변경하려면 @MickMacCallum의 대답을 참조하십시오. 프로세스에서 새 문자열을 생성하려면 substring(from:). 확장과 함께합니다 String, 당신의 추함을 숨길 수 substring(from:)substring(to:)시작과 끝을 잘라 유용한 추가를 만들 String:

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
        return substring(from: index(startIndex, offsetBy: count))
    }

    func chopSuffix(_ count: Int = 1) -> String {
        return substring(to: index(endIndex, offsetBy: -count))
    }
}

"hello".chopPrefix()    // "ello"
"hello".chopPrefix(3)   // "lo"

"hello".chopSuffix()    // "hell"
"hello".chopSuffix(3)   // "he"

마찬가지로 dropFirstdropLast그들 앞에,이 함수는 문자열에서 사용할 수있는 충분한 문자가없는 경우 충돌합니다. 발신자에게 적절하게 사용할 책임이 있습니다. 이것은 유효한 설계 결정입니다. 선택 사항을 반환하도록 작성하면 호출자가 풀어야합니다.


스위프트 2.x

에 아아 스위프트 2 , dropFirstdropLast(이전의 가장 좋은 방법은) 그들이 예전처럼 편리하지 않습니다. 확장명을 사용하면 및 String의 추악함을 숨길 수 있습니다 .substringFromIndexsubstringToIndex

extension String {
    func chopPrefix(count: Int = 1) -> String {
         return self.substringFromIndex(advance(self.startIndex, count))
    }

    func chopSuffix(count: Int = 1) -> String {
        return self.substringToIndex(advance(self.endIndex, -count))
    }
}

"hello".chopPrefix()    // "ello"
"hello".chopPrefix(3)   // "lo"

"hello".chopSuffix()    // "hell"
"hello".chopSuffix(3)   // "he"

마찬가지로 dropFirstdropLast그들 앞에,이 함수는 문자열에서 사용할 수있는 충분한 문자가없는 경우 충돌합니다. 발신자에게 적절하게 사용할 책임이 있습니다. 이것은 유효한 설계 결정입니다. 선택 사항을 반환하도록 작성하면 호출자가 풀어야합니다.


에서 스위프트 1.2 , 당신은 전화를해야합니다 chopPrefix다음과 같이 :

"hello".chopPrefix(count: 3)  // "lo"

또는 _함수 정의에 밑줄 을 추가 하여 매개 변수 이름을 억제 할 수 있습니다 .

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
         return self.substringFromIndex(advance(self.startIndex, count))
    }

    func chopSuffix(_ count: Int = 1) -> String {
        return self.substringToIndex(advance(self.endIndex, -count))
    }
}

3
나는 여전히 Swift의 내장 된 문자열 조작이 얼마나 복잡한 지에 놀랐습니다. 이것은 기본적이고 기본적인 것임을 의미합니다. 파서를 구현하는 것처럼 보이지 않아야합니다. 이것을 단순화하는 확장에 감사드립니다. Apple이 String 클래스에 이것을 추가하지 않을 것이라는 것은 당혹 스럽습니다! 아마도 여전히 유동적 일 것입니다.
devios1

이것이 그들이 "진화"아이라고 부르는 것입니다. 매일 처리 할 필요가 없다면 재미있을 것입니다. 나는 String API가있는 이유가 있다는 것을 알고 있지만, 실제로 이것은이 언어로의 많은 잠재적 인 변환을 연기해야합니다. 이전 댓글 작성자가 절대적으로 옳습니다. 이것은 기본적이고 기본적인 것이어야합니다.
Quintin Willison

17

스위프트 2.2

'advance'를 사용할 수 없음 : 인덱스에서 'advancedBy (n)'메서드를 호출합니다.

    func chopPrefix(count: Int = 1) -> String {
        return self.substringFromIndex(self.startIndex.advancedBy(count))
    }

    func chopSuffix(count: Int = 1) -> String {
        return self.substringFromIndex(self.endIndex.advancedBy(count))
    }

스위프트 3.0

    func chopPrefix(_ count: Int = 1) -> String {
        return self.substring(from: self.characters.index(self.startIndex, offsetBy: count))
    }

    func chopSuffix(_ count: Int = 1) -> String {
       return self.substring(to: self.characters.index(self.endIndex, offsetBy: -count))
    }

스위프트 3.2

문자 모음으로서의 문자열 내용보기.

@available(swift, deprecated: 3.2, message: "Please use String or Substring directly")
public var characters: String.CharacterView
func chopPrefix(_ count: Int = 1) -> String {
    if count >= 0 && count <= self.count {
        return self.substring(from: String.Index(encodedOffset: count))
    }
    return ""
}

func chopSuffix(_ count: Int = 1) -> String {
    if count >= 0 && count <= self.count {
        return self.substring(to: String.Index(encodedOffset: self.count - count))
    }
    return ""
}

스위프트 4

extension String {

    func chopPrefix(_ count: Int = 1) -> String {
        if count >= 0 && count <= self.count {
            let indexStartOfText = self.index(self.startIndex, offsetBy: count)
            return String(self[indexStartOfText...])
        }
        return ""
    }

    func chopSuffix(_ count: Int = 1) -> String {
        if count >= 0 && count <= self.count {
            let indexEndOfText = self.index(self.endIndex, offsetBy: -count)
            return String(self[..<indexEndOfText])
        }
        return ""
    }
}

1
chopSuffix 함수에 부정 -count를 추가하는 것을 잊은 것 같습니다
Andy


10

최종 결과가 무엇인지에 따라 다릅니다 (변이 vs 비변이).

Swift 4.1 기준 :

돌연변이 :

var str = "hello"
str.removeFirst() // changes str 

비변이 :

let str = "hello"
let strSlice = str.dropFirst() // makes a slice without the first letter
let str2 = String(strSlice)

노트:

  • nonmutating명확성 을 위해 예제에 추가 단계를 추가했습니다 . 주관적으로 마지막 두 단계를 결합하는 것이 더 간결합니다.
  • 의 이름은 dropFirst내가 이해하고있는 경우 때문에 나에게 조금 이상한 것 같다 스위프트 API 설계 지침을 제대로, dropFirst정말 같은 것을해야한다 dropingFirst는 nonmutating 때문이다. 그냥 생각 :).

1
실제로, 그것은 droppingFirst-그들은 엉망이되었습니다!
Fattie

6

이건 어때?

s.removeAtIndex(s.startIndex)

물론 이것은 문자열이 변경 가능하다고 가정합니다. 제거 된 문자를 반환하지만 원래 문자열을 변경합니다.


6

이전 답변은 꽤 좋지만 오늘 현재 Swift 4 의 문자열에서 첫 번째 문자를 제거하는 가장 간결한 방법이라고 생각합니다 .

var line: String = "This is a string..."
var char: Character? = nil

char = line.removeFirst()

print("char = \(char)")  // char = T
print("line = \(line)")  // line = his is a string ...

1

나는 기본적으로 더 간결한 것이 없다는 것을 알고 있지만 쉽게 prefix를 구현할 수 있습니다 ++.

public prefix func ++ <I: ForwardIndexType>(index: I) -> I {
    return advance(index, 1)
}

그 후 매우 간결하게 마음의 내용으로 사용할 수 있습니다.

str.substringFromIndex(++str.startIndex)

1

Swift 2에서는 다음 문자열 확장을 사용합니다.

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))
    }
}

display.text = display.text!.substringFromIndex(1)

1

"en_US, fr_CA, es_US".chopSuffix (5) .chopPrefix (5) // ", fr_CA,"

extension String {
    func chopPrefix(count: Int = 1) -> String {
        return self.substringFromIndex(self.startIndex.advancedBy(count))
    }

    func chopSuffix(count: Int = 1) -> String {
        return self.substringToIndex(self.endIndex.advancedBy(-count))
    }
}

0

문자열에서 첫 번째 문자를 제거하려면

let choppedString = String(txtField.text!.characters.dropFirst())

@JasonFoglia 나는 당신이 투표를 포기하는지 여부를 모르겠습니다. 아래 표를 주시면 자세히 설명해 주시겠습니까?
Hardik Thakkar

나는 이것을 다시 확인했고 그것이 정확하다는 것을 알았습니다. 나는 이것에 대해 적절하게 투표 할 수 있도록 대답을 편집했습니다.
Jason Foglia

0

다음은 확장 의 Swift4 충돌 저장 버전입니다 .chopPrefixchopSuffix

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
        return count>self.count ? self : String(self[index(self.startIndex, offsetBy: count)...])
    }
 }

0

Swift3

extension String {
    func chopPrefix(_ count: UInt = 1) -> String {
        return substring(from: characters.index(startIndex, offsetBy: Int(count)))
    }

    func chopSuffix(_ count: UInt = 1) -> String {
        return substring(to: characters.index(endIndex, offsetBy: -Int(count)))
    }
}

class StringChopTests: XCTestCase {
    func testPrefix() {
        XCTAssertEqual("original".chopPrefix(0), "original")
        XCTAssertEqual("Xfile".chopPrefix(), "file")
        XCTAssertEqual("filename.jpg".chopPrefix(4), "name.jpg")
    }

    func testSuffix() {
        XCTAssertEqual("original".chopSuffix(0), "original")
        XCTAssertEqual("fileX".chopSuffix(), "file")
        XCTAssertEqual("filename.jpg".chopSuffix(4), "filename")
    }
}

난 당신이 입력이 음의 값에 테스트 추가해야한다고 생각
무스타파 Baalbaki
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.