2015-04-26 4 views
3

Я хочу найти индекс последнего вхождения символа в String. Например, если моя строка "google.com/program/test", и я хочу найти письмо /, я хочу, чтобы моя функция возвращалась 18, потому что это последнее вхождение / в этой строке. Я попытался следовать Finding index of character in Swift String, а также попытался реализовать средство для прокрутки строки и просто найти последний индекс String с моим желаемым символом, но функция advance(), похоже, жалуется на получение Integer.Найти последнее появление символа в String?

var strCount = 0 
var lastSlashIndex = 0 
for i in urlAsString { 
    if i == "/"{ 
    if lastSlashIndex < strCount{ 
     lastSlashIndex = strCount 
    } 
    } 
    strCount++ 
} 

var endOfString = strCount - lastSlash 
//Cannot seem to use the advance function to get the remaining substring 
var fileName = urlAsString.substringFromIndex(advance(lastSlashIndex, endOfString)) 

Не может показаться, что это понятно, любая помощь будет оценена.

EDIT: Эта проблема не относится к конкретному символу '/'. Например, если строка "abbccd" и я ищу для письма 'c', то я хочу вернуть индекс 4, потому что это последний индекс, в котором 'c' происходит.

+0

Учитывая этот конкретный пример, ваш вопрос немного из проблемы XY. – nhgrif

+0

Прошу прощения, я не хотел делать это настолько конкретным. Я хочу просто найти последнее вхождение определенного персонажа. Это может быть любой символ. Например, если строка «abbccd», и я ищу букву «c», то я хочу вернуть индекс 4, потому что это последний индекс, в котором c встречается. @Nhgrif – user1871869

+0

Действительно ли это * что ты хочешь? Или вы действительно пытаетесь найти имя файла из строки, которая похожа на путь к файлу? Для этого есть очень простой однострочный лайнер ... – nhgrif

ответ

5

Вместо того, чтобы ответить на вопрос в заголовке, я взглянуть на вашем примере кода и предполагая, что это проблема XY. Если вам просто нужно удалить последний компонент пути (или получить только последний компонент пути), существуют существующие методы на NSString, которые делают это очень просто.

Если все, что вы хотите, это имя файла извлекается из пути:

let path = "/tmp/scratch.tiff" 
let fileName = path.lastPathComponent 

Это работает, даже когда path выглядит как своего рода URL.

let path = "https://www.dropbox.com/s/s73824fsda/FileName.ext" 
let fileName = path.lastPathComponent 
println(fileName) 

Печатается:

FileName.ext 

Как примечание, это работает, имеет ли последний компонент пути какой-либо расширения или любой другой. lastPathComponent просто возвращает все после последнего символа / (или если нет /, вся строка).

NSString фактически определяет довольно много методов для работы с файловыми путями (и все это работает на Swift's String). Я рекомендую взглянуть на official documentation. NSString имеет целый раздел методов под названием «Работа с путями».

+0

Документация для 'lastPathComponent' говорит' Обратите внимание, что этот метод только работает с файловыми путями (не, например, строковыми представлениями URL-адресов) .' – Hyperbole

2

Если вы хотите, чтобы найти первое вхождение персонажа, вы можете использовать функцию find, поэтому один из вариантов являются написать обратные найти эквивалент, по образцу обычной находки, а затем использовать это:

func rfind 
    <C: CollectionType 
     where C.Generator.Element: Equatable, 
      // one extra constraint needed - the ability 
      // to iterate backwards through the collection 
      C.Index: BidirectionalIndexType> 
    (domain: C, value: C.Generator.Element) -> C.Index? { 

    // the wrapping of the indices in reverse() is really 
    // the only difference between this and the regular find 
    for idx in reverse(indices(domain)) { 
     if domain[idx] == value { 
      return idx 
     } 
    } 
    return nil 
} 

Учитывая это, легко использовать его найти подстроку, разделенную последним вхождением символа:

let path = "/some/path/to/something" 

if let firstSlash = rfind(path, "/") { 
    let file = path[firstSlash.successor()..<path.endIndex] 
    println(file) // prints “something” 
} 

Конечно, вы можете просто написать цикл непосредственно в коде, если не хотите, чтобы проблема была решена при определении общей функции.

Примечание. Строки в Swift не являются случайным доступом через целые числа, это не имеет большого значения, поскольку нигде вам не нужно знать, что последняя косая черта - это n-й символ, просто индекс того, где он находится.

Если вы хотите, чтобы предположить отсутствие косой черты означает взять всю строку в качестве имени файла вы можете сделать:

let start = find(path, "/")?.successor() ?? path.startIndex 
let file = path[start..<path.endIndex] 
+0

Этот ответ велик, если мы хотим выполнять такие операции, основываясь на основном символе, отличном от '/'. Но для '/' существует целый набор методов, предназначенных для работы с файловыми путями. – nhgrif

+0

На самом деле, но я решил интерпретировать вопрос буквально :) прежде всего потому, что вопрос «как мне удалить путь из имени файла» почти наверняка является обманом ... –

0

Возможно, что @nhgrif прав, что это проблема XY, и что вы действительно хотите сделать, это проанализировать путь или URL-адрес, и есть встроенные методы в NSString и NSURL, чтобы сделать это для вас.

Если вы говорите о разборе строк общего назначения, для этого также существуют методы.

Безусловно, проще всего использовать метод NSString rangeOfString:options:. Одним из значений параметров является BackwardsSearch. Таким образом, вы передадите ему значение параметра BackwardsSearch. Вы вернете диапазон последних событий в строке поиска.

Я видел некоторые строковые методы Swift, которые используют версии Swift-ified диапазона, и неясно, какие методы NSString имеют собственные варианты Swift. (Я сам изучаю Swift.)

2

@ Duncan C предложил функцию rangeOfString.

Вот пример того, что это может выглядеть в Swift 2.0:

func lastIndexOf(s: String) -> Int? { 
    if let r: Range<Index> = self.rangeOfString(s, options: .BackwardsSearch) { 
     return self.startIndex.distanceTo(r.startIndex) 
    } 

    return Optional<Int>() 
} 

Тесты

func testStringLastIndexOf() { 
    let lastIndex = "google.com/program/test".lastIndexOf("/") 

    XCTAssertEqual(lastIndex, 18) 
} 

func testStringLastIndexOfNotFound() { 
    let lastIndex = "google.com".lastIndexOf("/") 

    XCTAssertEqual(lastIndex, nil); 
} 
0

Следующая выполняет эту задачу, используя расширение, которое может принимать строку вашего выбора, чтобы найти , Если он недоступен, вы получите нулевое значение, которое вы можете обработать.

extension String { 
    func lastOccurrenceOfString(string: String) -> String.Index? { 
     let characterSet = CharacterSet(charactersIn: string) 
     if let range = rangeOfCharacter(from: characterSet, options: .backwards) { 
      let offsetBy = distance(from: startIndex, to: range.upperBound) 

      return index(startIndex, offsetBy: offsetBy) 
     } 

     return nil 
    } 
} 

И следующие показывает это в использовании:

import UIKit 

class ViewController: UIViewController { 
    let testString = "google.com/program/test" 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     getIndex(of: "/") // 19 
     getIndex(of: ".") // 7 
     getIndex(of: "z") // N/A 
     getIndex(of: "me") // 21, e appears before m 
    } 

    func getIndex(of string: String) { 

     let slashIndex = testString.lastOccurrenceOfString(string: string) 
     print(slashIndex?.encodedOffset ?? "N/A") 
    } 
} 

extension String { 
    func lastOccurrenceOfString(string: String) -> String.Index? { 
     let characterSet = CharacterSet(charactersIn: string) 
     if let range = rangeOfCharacter(from: characterSet, options: .backwards) { 
      let offsetBy = distance(from: startIndex, to: range.upperBound) 

      return index(startIndex, offsetBy: offsetBy) 
     } 

     return nil 
    } 
} 
Смежные вопросы