是时候承认失败......
在Objective-C中,我可以使用类似的东西:
NSString* str = @"abcdefghi";
[str rangeOfString:@"c"].location; // 2
在Swift中,我看到类似的东西:
var str = "abcdefghi"
str.rangeOfString("c").startIndex
...但是这只给了我一个String.Index
,我可以用它来下标回原始字符串,但不能从中提取位置。
FWIW,String.Index
有一个名为_position
的私有ivar,其中包含正确的值。我只是不知道它是如何暴露的。
我知道我可以轻松地将此添加到String中。我对这个新API中缺少的内容更加好奇。
答案 0 :(得分:235)
你不是唯一一个找不到解决方案的人。
String
未实施RandomAccessIndexType
。可能是因为它们启用了具有不同字节长度的字符。这就是为什么我们必须使用string.characters.count
(Swift 1.x中的count
或countElements
)来获取字符数。这也适用于职位。 _position
可能是原始字节数组的索引,他们不希望公开它。 String.Index
旨在保护我们不要访问字符中间的字节。
这意味着您获得的任何索引都必须从String.startIndex
或String.endIndex
(String.Index
实现BidirectionalIndexType
)创建。可以使用successor
或predecessor
方法创建任何其他索引。
现在为了帮助我们索引,有一组方法(Swift 1.x中的函数):
Swift 4.x
let text = "abc"
let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let characterIndex2 = text.index(text.startIndex, offsetBy: 2)
let lastChar2 = text[characterIndex2] //will do the same as above
let range: Range<String.Index> = text.range(of: "b")!
let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
Swift 3.0
let text = "abc"
let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let characterIndex2 = text.characters.index(text.characters.startIndex, offsetBy: 2)
let lastChar2 = text.characters[characterIndex2] //will do the same as above
let range: Range<String.Index> = text.range(of: "b")!
let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
Swift 2.x
let text = "abc"
let index2 = text.startIndex.advancedBy(2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let lastChar2 = text.characters[index2] //will do the same as above
let range: Range<String.Index> = text.rangeOfString("b")!
let index: Int = text.startIndex.distanceTo(range.startIndex) //will call successor/predecessor several times until the indices match
Swift 1.x
let text = "abc"
let index2 = advance(text.startIndex, 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let range = text.rangeOfString("b")
let index: Int = distance(text.startIndex, range.startIndex) //will call succ/pred several times
使用String.Index
很麻烦,但使用包装器按整数索引(参见https://stackoverflow.com/a/25152652/669586)是危险的,因为它隐藏了真正索引的低效率。
请注意,Swift索引实现存在以下问题:为一个字符串创建的索引/范围无法可靠地用于其他字符串,例如:
Swift 2.x
let text: String = "abc"
let text2: String = ""
let range = text.rangeOfString("b")!
//can randomly return a bad substring or throw an exception
let substring: String = text2[range]
//the correct solution
let intIndex: Int = text.startIndex.distanceTo(range.startIndex)
let startIndex2 = text2.startIndex.advancedBy(intIndex)
let range2 = startIndex2...startIndex2
let substring: String = text2[range2]
Swift 1.x
let text: String = "abc"
let text2: String = ""
let range = text.rangeOfString("b")
//can randomly return nil or a bad substring
let substring: String = text2[range]
//the correct solution
let intIndex: Int = distance(text.startIndex, range.startIndex)
let startIndex2 = advance(text2.startIndex, intIndex)
let range2 = startIndex2...startIndex2
let substring: String = text2[range2]
答案 1 :(得分:86)
Swift 3.0 让这更加冗长:
let string = "Hello.World"
let needle: Character = "."
if let idx = string.characters.index(of: needle) {
let pos = string.characters.distance(from: string.startIndex, to: idx)
print("Found \(needle) at position \(pos)")
}
else {
print("Not found")
}
扩展:
extension String {
public func index(of char: Character) -> Int? {
if let idx = characters.index(of: char) {
return characters.distance(from: startIndex, to: idx)
}
return nil
}
}
在 Swift 2.0 中,这变得更加容易:
let string = "Hello.World"
let needle: Character = "."
if let idx = string.characters.indexOf(needle) {
let pos = string.startIndex.distanceTo(idx)
print("Found \(needle) at position \(pos)")
}
else {
print("Not found")
}
扩展:
extension String {
public func indexOfCharacter(char: Character) -> Int? {
if let idx = self.characters.indexOf(char) {
return self.startIndex.distanceTo(idx)
}
return nil
}
}
Swift 1.x实施:
对于纯粹的Swift解决方案,可以使用:
let string = "Hello.World"
let needle: Character = "."
if let idx = find(string, needle) {
let pos = distance(string.startIndex, idx)
println("Found \(needle) at position \(pos)")
}
else {
println("Not found")
}
作为String
的扩展名:
extension String {
public func indexOfCharacter(char: Character) -> Int? {
if let idx = find(self, char) {
return distance(self.startIndex, idx)
}
return nil
}
}
答案 2 :(得分:23)
extension String {
// MARK: - sub String
func substringToIndex(index:Int) -> String {
return self.substringToIndex(advance(self.startIndex, index))
}
func substringFromIndex(index:Int) -> String {
return self.substringFromIndex(advance(self.startIndex, 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)
}
subscript(index:Int) -> Character{
return self[advance(self.startIndex, index)]
}
subscript(range:Range<Int>) -> String {
let start = advance(self.startIndex, range.startIndex)
let end = advance(self.startIndex, range.endIndex)
return self[start..<end]
}
// MARK: - replace
func replaceCharactersInRange(range:Range<Int>, withString: String!) -> String {
var result:NSMutableString = NSMutableString(string: self)
result.replaceCharactersInRange(NSRange(range), withString: withString)
return result
}
}
答案 3 :(得分:16)
我找到了swift2的解决方案:
var str = "abcdefghi"
let indexForCharacterInString = str.characters.indexOf("c") //returns 2
答案 4 :(得分:8)
我不确定如何从String.Index中提取位置,但是如果你愿意退回到某些Objective-C框架,你可以桥接到objective-c并按照以前的方式进行操作。
"abcdefghi".bridgeToObjectiveC().rangeOfString("c").location
似乎某些NSString方法尚未(或可能不会)移植到String。包含也会浮现在脑海中。
答案 5 :(得分:8)
这是一个干净的String扩展,它回答了这个问题:
斯威夫特3:
extension String {
var length:Int {
return self.characters.count
}
func indexOf(target: String) -> Int? {
let range = (self as NSString).range(of: target)
guard range.toRange() != nil else {
return nil
}
return range.location
}
func lastIndexOf(target: String) -> Int? {
let range = (self as NSString).range(of: target, options: NSString.CompareOptions.backwards)
guard range.toRange() != nil else {
return nil
}
return self.length - range.location - 1
}
func contains(s: String) -> Bool {
return (self.range(of: s) != nil) ? true : false
}
}
Swift 2.2:
extension String {
var length:Int {
return self.characters.count
}
func indexOf(target: String) -> Int? {
let range = (self as NSString).rangeOfString(target)
guard range.toRange() != nil else {
return nil
}
return range.location
}
func lastIndexOf(target: String) -> Int? {
let range = (self as NSString).rangeOfString(target, options: NSStringCompareOptions.BackwardsSearch)
guard range.toRange() != nil else {
return nil
}
return self.length - range.location - 1
}
func contains(s: String) -> Bool {
return (self.rangeOfString(s) != nil) ? true : false
}
}
答案 6 :(得分:5)
如果你想使用熟悉的NSString,你可以明确地声明它:
var someString: NSString = "abcdefghi"
var someRange: NSRange = someString.rangeOfString("c")
我还不确定如何在Swift中执行此操作。
答案 7 :(得分:4)
如果您想知道字符串中字符的位置为 int 值,请使用以下代码:
let loc = newString.range(of: ".").location
答案 8 :(得分:4)
您还可以在单个字符串中找到字符的索引,如
extension String {
func indexes(of character: String) -> [Int] {
precondition(character.count == 1, "Must be single character")
return self.enumerated().reduce([]) { partial, element in
if String(element.element) == character {
return partial + [element.offset]
}
return partial
}
}
}
在[String.Distance]中给出结果即。 [Int],如
"apple".indexes(of: "p") // [1, 2]
"element".indexes(of: "e") // [0, 2, 4]
"swift".indexes(of: "j") // []
答案 9 :(得分:3)
我知道这已经过时了,答案已被接受,但你可以使用以下几行代码找到字符串的索引:
var str : String = "abcdefghi"
let characterToFind: Character = "c"
let characterIndex = find(str, characterToFind) //returns 2
此处有关Swift字符串的其他一些重要信息Strings in Swift
答案 10 :(得分:3)
Swift 4.0
func indexInt(of char: Character) -> Int? {
return index(of: char)?.encodedOffset
}
答案 11 :(得分:2)
如果您考虑一下,您实际上并不需要该位置的确切Int版本。 Range或甚至String.Index足以在需要时再次输出子字符串:
let myString = "hello"
let rangeOfE = myString.rangeOfString("e")
if let rangeOfE = rangeOfE {
myString.substringWithRange(rangeOfE) // e
myString[rangeOfE] // e
// if you do want to create your own range
// you can keep the index as a String.Index type
let index = rangeOfE.startIndex
myString.substringWithRange(Range<String.Index>(start: index, end: advance(index, 1))) // e
// if you really really need the
// Int version of the index:
let numericIndex = distance(index, advance(index, 1)) // 1 (type Int)
}
答案 12 :(得分:2)
Swift中的变量类型String与Objective-C中的NSString相比包含不同的函数。正如Sulthan所说,
Swift String没有实现RandomAccessIndex
你可以做的是将String类型的变量向下转换为NSString(这在Swift中是有效的)。这将使您可以访问NSString中的函数。
var str = "abcdefghi" as NSString
str.rangeOfString("c").locationx // returns 2
答案 13 :(得分:2)
这对我有用,
var loc = "abcdefghi".rangeOfString("c").location
NSLog("%d", loc);
这也有效,
var myRange: NSRange = "abcdefghi".rangeOfString("c")
var loc = myRange.location
NSLog("%d", loc);
答案 14 :(得分:2)
最简单的方法是:
在 Swift 3 :
var textViewString:String = "HelloWorld2016"
guard let index = textViewString.characters.index(of: "W") else { return }
let mentionPosition = textViewString.distance(from: index, to: textViewString.endIndex)
print(mentionPosition)
答案 15 :(得分:1)
String是NSString的桥接类型,因此添加
import Cocoa
到您的swift文件并使用所有“旧”方法。
答案 16 :(得分:1)
在思考方面,这可能被称为反转。你发现世界是圆的而不是扁平的。 &#34;你真的不需要知道角色的INDEX来做它的事情。&#34;作为一名C程序员,我发现很难接受! 你的行&#34;让index = letters.characters.indexOf(&#34; c&#34;)!&#34;本身就足够了。 例如,要删除c,您可以使用...(游乐场粘贴)
var letters = "abcdefg"
//let index = letters.rangeOfString("c")!.startIndex //is the same as
let index = letters.characters.indexOf("c")!
range = letters.characters.indexOf("c")!...letters.characters.indexOf("c")!
letters.removeRange(range)
letters
但是,如果你想要一个索引,你需要返回一个实际的INDEX,而不是Int作为一个Int值需要额外的步骤才能实际使用。这些扩展返回索引,特定字符的计数以及此游乐场可插入代码将演示的范围。
extension String
{
public func firstIndexOfCharacter(aCharacter: Character) -> String.CharacterView.Index? {
for index in self.characters.indices {
if self[index] == aCharacter {
return index
}
}
return nil
}
public func returnCountOfThisCharacterInString(aCharacter: Character) -> Int? {
var count = 0
for letters in self.characters{
if aCharacter == letters{
count++
}
}
return count
}
public func rangeToCharacterFromStart(aCharacter: Character) -> Range<Index>? {
for index in self.characters.indices {
if self[index] == aCharacter {
let range = self.startIndex...index
return range
}
}
return nil
}
}
var MyLittleString = "MyVery:important String"
var theIndex = MyLittleString.firstIndexOfCharacter(":")
var countOfColons = MyLittleString.returnCountOfThisCharacterInString(":")
var theCharacterAtIndex:Character = MyLittleString[theIndex!]
var theRange = MyLittleString.rangeToCharacterFromStart(":")
MyLittleString.removeRange(theRange!)
答案 17 :(得分:1)
Swift 4完整解决方案:
OffsetIndexableCollection(使用Int索引的字符串)
https://github.com/frogcjn/OffsetIndexableCollection-String-Int-Indexable-
let a = "01234"
print(a[0]) // 0
print(a[0...4]) // 01234
print(a[...]) // 01234
print(a[..<2]) // 01
print(a[...2]) // 012
print(a[2...]) // 234
print(a[2...3]) // 23
print(a[2...2]) // 2
if let number = a.index(of: "1") {
print(number) // 1
print(a[number...]) // 1234
}
if let number = a.index(where: { $0 > "1" }) {
print(number) // 2
}
答案 18 :(得分:0)
查找子字符串的索引
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: Int = str.distance(from: str.startIndex, to: firstIndex)
print("index: ", index) //index: 2
}
else {
print("symbol not found")
}
答案 19 :(得分:0)
您可以使用以下命令在字符串中找到字符的索引号:
var str = "abcdefghi"
if let index = str.firstIndex(of: "c") {
let distance = str.distance(from: str.startIndex, to: index)
// distance is 2
}
答案 20 :(得分:0)
以我的观点,了解逻辑本身的更好方法在下面
let testStr: String = "I love my family if you Love us to tell us I'm with you"
var newStr = ""
let char:Character = "i"
for value in testStr {
if value == char {
newStr = newStr + String(value)
}
}
print(newStr.count)
答案 21 :(得分:0)
关于将 ##Assembly-Data-START##
Sequencing Technology :: Sanger dideoxy sequencing
##Assembly-Data-END##
变为String.Index
的主题,此扩展适用于我:
Int
与此问题相关的示例用法:
public extension Int {
/// Creates an `Int` from a given index in a given string
///
/// - Parameters:
/// - index: The index to convert to an `Int`
/// - string: The string from which `index` came
init(_ index: String.Index, in string: String) {
self.init(string.distance(from: string.startIndex, to: index))
}
}
正如您所知,它对扩展的字形集群进行了分组,并且加入的字符与var testString = "abcdefg"
Int(testString.range(of: "c")!.lowerBound, in: testString) // 2
testString = "\u{1112}\u{1161}\u{11AB}"
Int(testString.range(of: "")!.lowerBound, in: testString) // 0
Int(testString.range(of: "")!.lowerBound, in: testString) // 1
Int(testString.range(of: "한")!.lowerBound, in: testString) // 5
不同。当然,这就是我们String.Index
的原因。您应该记住,此方法将群集视为单个字符,这更接近正确。 如果您的目标是通过Unicode代码点拆分字符串,那么这不适合您。
答案 22 :(得分:0)
如果你只需要一个字符的索引,最简单,快速的解决方案(正如Pascal已经指出的那样)是:
let index = string.characters.index(of: ".")
let intIndex = string.distance(from: string.startIndex, to: index)
答案 23 :(得分:0)
我玩下面的
extension String {
func allCharactes() -> [Character] {
var result: [Character] = []
for c in self.characters {
result.append(c)
}
return
}
}
直到我理解提供的那个,现在它只是字符数组
和
let c = Array(str.characters)
答案 24 :(得分:0)
let mystring:String = "indeep";
let findCharacter:Character = "d";
if (mystring.characters.contains(findCharacter))
{
let position = mystring.characters.indexOf(findCharacter);
NSLog("Position of c is \(mystring.startIndex.distanceTo(position!))")
}
else
{
NSLog("Position of c is not found");
}
答案 25 :(得分:0)
在 Swift 2.0 中,以下函数返回给定字符前的子字符串。
func substring(before sub: String) -> String {
if let range = self.rangeOfString(sub),
let index: Int = self.startIndex.distanceTo(range.startIndex) {
return sub_range(0, index)
}
return ""
}
答案 26 :(得分:0)
使用Swift 2获取字符串中子字符串的索引:
let text = "abc"
if let range = text.rangeOfString("b") {
var index: Int = text.startIndex.distanceTo(range.startIndex)
...
}
答案 27 :(得分:0)
如果您正在寻找获取字符或字符串索引的简便方法,请检查此库http://www.dollarswift.org/#indexof-char-character-int
您可以使用另一个字符串或正则表达式
从字符串中获取indexOf答案 28 :(得分:-1)
extension String {
func substring(from:String) -> String
{
let searchingString = from
let rangeOfSearchingString = self.range(of: searchingString)!
let indexOfSearchingString: Int = self.distance(from: self.startIndex, to: rangeOfSearchingString.upperBound )
let trimmedString = self.substring(start: indexOfSearchingString , end: self.count)
return trimmedString
}
}
答案 29 :(得分:-1)
// Using Swift 4, the code below works.
// The problem is that String.index is a struct. Use dot notation to grab the integer part of it that you want: ".encodedOffset"
let strx = "0123456789ABCDEF"
let si = strx.index(of: "A")
let i = si?.encodedOffset // i will be an Int. You need "?" because it might be nil, no such character found.
if i != nil { // You MUST deal with the optional, unwrap it only if not nil.
print("i = ",i)
print("i = ",i!) // "!" str1ps off "optional" specification (unwraps i).
// or
let ii = i!
print("ii = ",ii)
}
// Good luck.