Swift를 사용하는 문자열의 하위 문자열 인덱스
JavaScript에서 이 작업에 익숙합니다.
var domains = "abcde".substring(0, "abcde".indexOf("cd")) // Returns "ab"
스위프트는 이 기능이 없는데, 비슷한 것을 어떻게 하나요?
편집/업데이트:
Xcode 11.4 • Swift 5.2 이상
import Foundation
extension StringProtocol {
func index<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? {
range(of: string, options: options)?.lowerBound
}
func endIndex<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? {
range(of: string, options: options)?.upperBound
}
func indices<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Index] {
ranges(of: string, options: options).map(\.lowerBound)
}
func ranges<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Range<Index>] {
var result: [Range<Index>] = []
var startIndex = self.startIndex
while startIndex < endIndex,
let range = self[startIndex...]
.range(of: string, options: options) {
result.append(range)
startIndex = range.lowerBound < range.upperBound ? range.upperBound :
index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
}
return result
}
}
용도:
let str = "abcde"
if let index = str.index(of: "cd") {
let substring = str[..<index] // ab
let string = String(substring)
print(string) // "ab\n"
}
let str = "Hello, playground, playground, playground"
str.index(of: "play") // 7
str.endIndex(of: "play") // 11
str.indices(of: "play") // [7, 19, 31]
str.ranges(of: "play") // [{lowerBound 7, upperBound 11}, {lowerBound 19, upperBound 23}, {lowerBound 31, upperBound 35}]
대소문자를 구분하지 않는 샘플
let query = "Play"
let ranges = str.ranges(of: query, options: .caseInsensitive)
let matches = ranges.map { str[$0] } //
print(matches) // ["play", "play", "play"]
정규식 샘플
let query = "play"
let escapedQuery = NSRegularExpression.escapedPattern(for: query)
let pattern = "\\b\(escapedQuery)\\w+" // matches any word that starts with "play" prefix
let ranges = str.ranges(of: pattern, options: .regularExpression)
let matches = ranges.map { str[$0] }
print(matches) // ["playground", "playground", "playground"]
첨자를 사용하여 하위 문자열을 얻을 수 있습니다.범위를 만들려면 시작 인덱스와 마지막 인덱스가 필요하며 아래와 같이 할 수 있습니다.
let str = "abcde"
if let range = str.range(of: "cd") {
let substring = str[..<range.lowerBound] // or str[str.startIndex..<range.lowerBound]
print(substring) // Prints ab
}
else {
print("String not present")
}
시작 인덱스를 정의하지 않으면 이 연산자..<
시작 인덱스를 사용합니다.사용할 수도 있습니다.str[str.startIndex..<range.lowerBound]
대신에str[..<range.lowerBound]
스위프트 5
하위 문자열 인덱스 찾기
let str = "abcdecd"
if let range: Range<String.Index> = str.range(of: "cd") {
let index: Int = str.distance(from: str.startIndex, to: range.lowerBound)
print("index: ", index) //index: 2
}
else {
print("substring not found")
}
문자 색인 찾기
let str = "abcdecd"
if let firstIndex = str.firstIndex(of: "c") {
let index = str.distance(from: str.startIndex, to: firstIndex)
print("index: ", index) //index: 2
}
else {
print("symbol not found")
}
Swift 4에서:
문자열에 있는 문자의 인덱스를 가져오는 중
let str = "abcdefghabcd"
if let index = str.index(of: "b") {
print(index) // Index(_compoundOffset: 4, _cache: Swift.String.Index._Cache.character(1))
}
Swift 4를 사용하여 String에서 SubString(접두사 및 접미사) 만들기:
let str : String = "ilike"
for i in 0...str.count {
let index = str.index(str.startIndex, offsetBy: i) // String.Index
let prefix = str[..<index] // String.SubSequence
let suffix = str[index...] // String.SubSequence
print("prefix \(prefix), suffix : \(suffix)")
}
산출량
prefix , suffix : ilike
prefix i, suffix : like
prefix il, suffix : ike
prefix ili, suffix : ke
prefix ilik, suffix : e
prefix ilike, suffix :
두 인덱스 사이에 부분 문자열을 생성하려면 다음을 사용합니다.
let substring1 = string[startIndex...endIndex] // including endIndex
let subString2 = string[startIndex..<endIndex] // excluding endIndex
Swift에서 이 작업을 수행하는 것은 가능하지만 더 많은 라인이 필요합니다. 여기에 기능이 있습니다.indexOf()
예상되는 일을 하는 것:
func indexOf(source: String, substring: String) -> Int? {
let maxIndex = source.characters.count - substring.characters.count
for index in 0...maxIndex {
let rangeSubstring = source.startIndex.advancedBy(index)..<source.startIndex.advancedBy(index + substring.characters.count)
if source.substringWithRange(rangeSubstring) == substring {
return index
}
}
return nil
}
var str = "abcde"
if let indexOfCD = indexOf(str, substring: "cd") {
let distance = str.startIndex.advancedBy(indexOfCD)
print(str.substringToIndex(distance)) // Returns "ab"
}
이 함수는 최적화되지 않았지만 짧은 문자열에 대해 작업을 수행합니다.
여기에는 밀접하게 연결된 세 가지 문제가 있습니다.
모든 하위 문자열 찾기 방법은 Cocoa NSString 세계에서 끝납니다(Foundation).
Foundation NSRange가 SwiftRange와 일치하지 않습니다. 전자는 시작 및 길이를 사용하고 후자는 끝점을 사용합니다.
일반적으로 Swift 문자는 다음을 사용하여 인덱싱됩니다.
String.Index
Int는 아니지만, Foundation 문자는 Int를 사용하여 인덱싱되며, 이들 사이에는 간단한 직역이 없습니다(Foundation과 Swift는 문자를 구성하는 것에 대한 아이디어가 다르기 때문입니다).
이 모든 것을 고려하여, 다음과 같은 글을 쓰는 방법에 대해 생각해 보겠습니다.
func substring(of s: String, from:Int, toSubstring s2 : String) -> Substring? {
// ?
}
서브스트링s2
에서 찾아야 합니다.s
String Foundation 메서드를 사용합니다.결과 범위는 NSRange가 아니라(이것이 Foundation 메서드임에도 불구하고) 다음의 범위로 반환됩니다.String.Index
(부분 문자열을 전혀 찾지 못한 경우를 대비하여 옵션으로 포장).하지만, 다른 숫자는,from
인트입니다.따라서 우리는 두 가지 모두를 포함하는 어떤 종류의 범위도 형성할 수 없습니다.
하지만 그럴 필요는 없어요!우리가 해야 할 일은 원래 문자열의 끝을 잘라내는 것입니다.String.Index
그리고 Int를 취하는 방법을 사용하여 원래 문자열의 시작 부분을 잘라냅니다.다행히도, 그러한 방법들이 존재합니다!다음과 같이:
func substring(of s: String, from:Int, toSubstring s2 : String) -> Substring? {
guard let r = s.range(of:s2) else {return nil}
var s = s.prefix(upTo:r.lowerBound)
s = s.dropFirst(from)
return s
}
아니면, 이 방법을 문자열에 직접 적용할 수 있다면, 이렇게...
let output = "abcde".substring(from:0, toSubstring:"cd")
...그런 다음 String의 확장자로 만듭니다.
extension String {
func substring(from:Int, toSubstring s2 : String) -> Substring? {
guard let r = self.range(of:s2) else {return nil}
var s = self.prefix(upTo:r.lowerBound)
s = s.dropFirst(from)
return s
}
}
스위프트 5
let alphabet = "abcdefghijklmnopqrstuvwxyz"
var index: Int = 0
if let range: Range<String.Index> = alphabet.range(of: "c") {
index = alphabet.distance(from: alphabet.startIndex, to: range.lowerBound)
print("index: ", index) //index: 2
}
스위프트 5
extension String {
enum SearchDirection {
case first, last
}
func characterIndex(of character: Character, direction: String.SearchDirection) -> Int? {
let fn = direction == .first ? firstIndex : lastIndex
if let stringIndex: String.Index = fn(character) {
let index: Int = distance(from: startIndex, to: stringIndex)
return index
} else {
return nil
}
}
}
테스트:
func testFirstIndex() {
let res = ".".characterIndex(of: ".", direction: .first)
XCTAssert(res == 0)
}
func testFirstIndex1() {
let res = "12345678900.".characterIndex(of: "0", direction: .first)
XCTAssert(res == 9)
}
func testFirstIndex2() {
let res = ".".characterIndex(of: ".", direction: .last)
XCTAssert(res == 0)
}
func testFirstIndex3() {
let res = "12345678900.".characterIndex(of: "0", direction: .last)
XCTAssert(res == 10)
}
Swift 버전 3에서 String은 다음과 같은 기능을 가지고 있지 않습니다.
str.index(of: String)
하위 문자열에 인덱스가 필요한 경우 범위를 가져오는 방법 중 하나입니다.문자열에 범위를 반환하는 다음 함수가 있습니다.
str.range(of: <String>)
str.rangeOfCharacter(from: <CharacterSet>)
str.range(of: <String>, options: <String.CompareOptions>, range: <Range<String.Index>?>, locale: <Locale?>)
예를 들어 str에서 처음 발생하는 재생의 인덱스를 찾는 방법
var str = "play play play"
var range = str.range(of: "play")
range?.lowerBound //Result : 0
range?.upperBound //Result : 4
참고: 범위는 선택 사항입니다.문자열을 찾을 수 없으면 0이 됩니다.예를들면
var str = "play play play"
var range = str.range(of: "zoo") //Result : nil
range?.lowerBound //Result : nil
range?.upperBound //Result : nil
레오 다부스의 대답은 훌륭합니다.다음은 그의 대답에 근거한 나의 대답입니다.compactMap
해서를 Index out of range
message
스위프트 5.1
extension StringProtocol {
func ranges(of targetString: Self, options: String.CompareOptions = [], locale: Locale? = nil) -> [Range<String.Index>] {
let result: [Range<String.Index>] = self.indices.compactMap { startIndex in
let targetStringEndIndex = index(startIndex, offsetBy: targetString.count, limitedBy: endIndex) ?? endIndex
return range(of: targetString, options: options, range: startIndex..<targetStringEndIndex, locale: locale)
}
return result
}
}
// Usage
let str = "Hello, playground, playground, playground"
let ranges = str.ranges(of: "play")
ranges.forEach {
print("[\($0.lowerBound.utf16Offset(in: str)), \($0.upperBound.utf16Offset(in: str))]")
}
// result - [7, 11], [19, 23], [31, 35]
NSRange 사용을 고려해 보셨습니까?
if let range = mainString.range(of: mySubString) {
//...
}
언급URL : https://stackoverflow.com/questions/32305891/index-of-a-substring-in-a-string-with-swift
'programing' 카테고리의 다른 글
'1004': "정렬 참조가 잘못되었습니다." (0) | 2023.08.18 |
---|---|
각 개체에 대해 다음 항목으로 이동 (0) | 2023.08.18 |
선택을 취소하는 가장 좋은 방법선택을 취소하는 가장 좋은 방법선택을 취소하는 가장 좋은 방법 (0) | 2023.08.18 |
"col-xs-*"이 Bootstrap 4에서 작동하지 않음 (0) | 2023.08.18 |
SmtpClient를 사용하여 C#을 통해 HTML 전자 메일 보내기 (0) | 2023.08.18 |