如何在Swift中通过新行拆分字符串

jutyujz0  于 2023-03-07  发布在  Swift
关注(0)|答案(9)|浏览(173)

我有一个字符串,我从一个文本文件。
文本文件:

Line 1
Line 2
Line 3
...

我想把它转换成一个数组,每行一个数组元素。

[ "Line 1", "Line 2", "Line 3", ... ]

根据文件的保存方式,字符串可以采用以下形式之一:

  • string = "Line 1\nLine 2\nLine 3\n..."其中\n是新行(换行符)字符
  • string = "Line 1\r\nLine 2\r\nLine 3\r\n...",其中\r是回车符。

据我所知,\n是目前苹果/Linux中常用的,而\r\n是Windows中常用的。
如何在任意一个换行符处拆分字符串,以得到一个没有空元素的String数组?

更新

下面有几个解决方案。在这一点上,我没有任何令人信服的理由选择一个比其他更正确。一些可能影响选择的因素可能是(1)它有多"迅速",(2)它对很长的字符串有多快。你可以通过投票一个或多个和/或留下评论来提供反馈。

okxuctiv

okxuctiv1#

    • Swift 5.2或更高版本**

可以使用新的Character属性isNewline拆分String

let sentence = "Line 1\nLine 2\nLine 3\n"
let lines = sentence.split(whereSeparator: \.isNewline)
print(lines)   // "["Line 1", "Line 2", "Line 3"]\n"

您还可以扩展StringProtocol并创建lines示例属性,以将字符串行分解为子序列:
x一个一个一个一个x一个一个二个x

    • 原始答案**

您可以使用字符串方法enumerateLines
枚举字符串中的所有行。

    • Swift 3或更高版本**

一个一个三个一个一个一个一个一个四个一个一个一个一个一个五个一个

vh0rcniy

vh0rcniy2#

Xcode 8.2和Swift 3.0.1中:
使用NSString方法组件(以:分隔)

let text = "line1\nline2"
let array = text.components(separatedBy: CharacterSet.newlines)

或者使用String方法enumerateLines,如Leo Dabus的答案

nr7wwzry

nr7wwzry3#

在Swift 2中,顶层split函数现在是CollectionType上的一个方法(String的每个"字符视图"都符合这个方法)。这个方法有两个版本,您需要一个将闭包作为 predicate 的方法,以指示给定的元素是否应该被视为分隔符。
可以使用string.utf16从字符串中获取字符集合,作为UTF16字符的集合,使其与NSCharacterSet API兼容。这样,我们可以很容易地在闭包内部检查字符串中的给定字符是否是换行符集的成员。
值得注意的是,split(_:)将返回SubSequence字符(基本上是一个Slice),所以它需要转换回一个字符串数组,这通常更有用。我已经在下面使用flatMap(String.init)完成了这一操作-String上的UTF16View初始化程序是失败的,因此使用flatMap将忽略任何可能返回的nil值,确保您返回的是非可选字符串数组。
因此,有一种类似Swift的好方法:

let str = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lines = str.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init)
// lines = ["Line 1", "Line 2", "Line 3"]

split方法有一个参数allowEmptySubsequences,它确保在结果中不会收到任何空字符序列,默认值是false,所以实际上根本不需要指定它。

编辑

如果您想完全避免使用NSCharacterSet,您可以很容易地拆分符合unicode的Character集合。

let lines = str.characters.split { $0 == "\n" || $0 == "\r\n" }.map(String.init)

Swift可以将"\r\n"视为一个扩展的字素簇,将其作为一个Character用于比较,而不是创建一个String。还要注意的是,从Character创建字符串的初始化器是不可失败的,所以我们可以只使用map

p1tboqfb

p1tboqfb4#

这个答案是对已经给出的其他解决方案的总结,它来自我的fuller answer,但是在这里提供实际的方法选择会很有用。
新行通常使用\n字符,但也可以使用\r\n(从保存在Windows中的文件)。

溶液

    • 1.一米二英寸一英寸**
let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.componentsSeparatedByCharactersInSet(newlineChars).filter{!$0.isEmpty}
// "[Line 1, Line 2, Line 3]"

如果不使用filter,则\r\n将生成一个空数组元素,因为它被计为两个字符,因此在同一位置将字符串分隔两次。

    • 2.一米五英寸一英寸**
let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init)
// "[Line 1, Line 2, Line 3]"

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let lineArray = multiLineString.characters.split { $0 == "\n" || $0 == "\r\n" }.map(String.init)
// "[Line 1, Line 2, Line 3]"

这里\r\n被计为单个Swift字符(扩展的字素簇)

    • 3.一米七三英寸**
let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
var lineArray = [String]()
multiLineString.enumerateLines { (line, stop) -> () in
    lineArray.append(line)
}
// "[Line 1, Line 2, Line 3]"

有关enumerateLine语法的更多信息,请参见this answer

备注:

  • 一个多行字符串通常不会混合\r\n\n,但我在这里这样做是为了说明这些方法可以处理这两种格式。
  • NSCharacterSet.newlineCharacterSet()是定义为(U +000A-U +000D,U +0085)的换行符,包括\r\n
  • 此答案是上一个问题答案的摘要。有关详细信息,请阅读这些答案。
4smxwvx5

4smxwvx55#

let test1 = "Line1\n\rLine2\nLine3\rLine4"
let t1 = test1.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
let t2 = t1.filter{ $0 != "" }
let t3 = t1.filter{ !$0.isEmpty }
o2rvlv0m

o2rvlv0m6#

为了记录在案,Swift的基础CharacterSet可用于拆分:

备选方案1

extension String {
    var lines: [String] {
        return split { String($0).rangeOfCharacter(from: .newlines) != nil }.map(String.init)
    }
}

备选方案2

extension String {
    var lines: [String] {
        return split { CharacterSet.newlines.contains($0.unicodeScalars.first!) }.map(String.init)
    }
}
pb3skfrl

pb3skfrl7#

如何在任意一个换行符处拆分字符串,以得到一个没有空元素的String数组?
你就快到了--只是尾部闭包不同而已:

let array = stringFromFile.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()).filter{!$0.isEmpty}

这与以下内容相同:

let newLineChars = NSCharacterSet.newlineCharacterSet() // newline characters defined as (U+000A–U+000D, U+0085)
let array = stringFromFile.componentsSeparatedByCharactersInSet(newLineChars).filter{!$0.isEmpty}

ETA:删除尾部闭合处不必要的额外支架

iszxjhcz

iszxjhcz8#

雨燕4:

我建议您先将CSV保存为字符串,如果您还没有这样做的话,然后通过删除不必要的回车来“清理”字符串

let dataString = String(data: yourData!, encoding: .utf8)!

        var cleanFile = dataString.replacingOccurrences(of: "\r", with: "\n")
        cleanFile = cleanFile.replacingOccurrences(of: "\n\n", with: "\n")

上面将给予一个具有最理想格式的字符串,然后您可以使用\n作为分隔符来分隔字符串:

let csvStrings = cleanFile.components(separatedBy: ["\n"])

现在您有一个包含3个项目的数组,如下所示:

[“第一行”、“第二行”、“第三行”]

我正在使用CSV文件,完成此操作后,我将项目拆分为组件,因此,如果您的项目类似于:
[“第1行、第2行、第3行”、“第A行、第B行、第C行”]

let component0 = csvStrings[0].components(separatedBy: [","]) // ["Line1","Line2","Line3"]
        let component1 = csvStrings[1].components(separatedBy: [","]) // ["LineA","LineB","LineC"]
mnemlml8

mnemlml89#

let getName = "Davender+Verma"
     let cleanFile = getName.replacingOccurrences(of: "+", with: "+\n")
     self.upcomingViewPetName.text = cleanFile

     Output: Davender+
            verma

Or 
     let getName = "Davender+Verma"
     let cleanFile = getName.replacingOccurrences(of: "+", with: "\n")
     self.upcomingViewPetName.text = cleanFile

Output:     Davender
            verma

相关问题