web-dev-qa-db-ja.com

Swiftで文字列を改行で分割する方法

テキストファイルから取得した文字列があります。

テキストファイル:

Line 1
Line 2
Line 3
...

1行に1つの配列要素を配列に変換したいと思います。

[ "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は今日、Apple/Linuxで一般的に使用されていますが、\r\nはWindowsで使用されます。

空の要素のない文字列配列を取得するには、どのように文字列を改行で分割しますか?

更新

以下の解決策がいくつかあります。この時点では、他の選択肢よりも正しいものを1つ選択する強い理由はありません。選択に影響を与える可能性のあるいくつかの要因は、(1)それがいかに「迅速」であるか、および(2)非常に長い文字列の場合にどれほど速いかである可能性があります。それらの1つ以上を賛成するか、コメントを残してフィードバックを提供できます。

ここに私の要約された答えを参照してください

37
Suragch

Swift 5以降

新しいStringプロパティを使用してCharacterを分割できます isNewline

let sentence = "Line 1\nLine 2\nLine 3\n"
var lines = sentence.split { $0.isNewline }
print(lines)   // "[Line 1, Line 2, Line 3]"

元の回答

StringメソッドenumerateLinesを使用できます。

文字列のすべての行を列挙します。

Swift 3以降

let sentence = "Line 1\nLine 2\nLine 3\n"
var lines: [String] = []
sentence.enumerateLines { line, _ in
    lines.append(line)
}
print(lines)   // "[Line 1, Line 2, Line 3]"

extension String {
    var lines: [String] {
        var result: [String] = []
        enumerateLines { line, _ in result.append(line) }
        return result
    }
}

使用法:

let sentence2 = "Line 4\nLine 5\nLine 6\n"
let sentence2Lines = sentence2.lines

print(sentence2Lines)    // ["Line 4", "Line 5", "Line 6"]


let sentence3 = "Line 7\r\nLine 8\r\nLine 9\r\n"
let sentence3Lines = sentence3.lines

print(sentence3Lines)  // "[Line 7, Line 8, Line 9]"
64
Leo Dabus

Xcode 8.2、Swift 3.0.1:

NSStringメソッドを使用components(separatedBy:)

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

または、Leo Dabusの回答のように、StringメソッドenumerateLinesを使用します

20
zagger

Swift 2では、トップレベルのsplit関数がCollectionTypeのメソッドになりました(これは、Stringsの「文字ビュー」のそれぞれが準拠します) to)メソッドには2つのバージョンがあり、特定の要素をセパレーターとして扱う必要があるかどうかを示す述語としてクロージャーを使用するバージョンが必要です。

_string.utf16_を使用して文字列から文字コレクションからUTF16文字のコレクションを取得し、NSCharacterSet AP​​Iと互換性を持たせることができます。このようにして、文字列内の特定の文字が改行文字セットのメンバーであるかどうかをクロージャー内で簡単に確認できます。

split(_:)SubSequenceの文字(基本的にはSlice)を返すため、通常はより有用な文字列の配列に変換し直す必要があることに注意してください。 flatMap(String.init)を使用してこれを実行しました-Stringの_UTF16View_イニシャライザは失敗する可能性があるため、flatMapを使用するとnilの値は無視されますこれは返される可能性があり、オプションではない文字列の配列を確実に取得します。

だから、これを行うためのNice 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準拠のCharactersのコレクションを簡単に分割できます。

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

Swiftは_"\r\n"_を単一の拡張書記素クラスターとして扱い、Characterを作成する代わりにそれを単一のStringとして比​​較に使用できます。また、Characterから文字列を作成するためのイニシャライザは失敗しないため、mapのみを使用できます。

9
Stuart

この回答は、すでに提供されている他のソリューションの要約です。それは私の より完全な答え から来ていますが、実際の方法の選択肢をここで利用できると便利です。

新しい行は通常_\n_文字で作成されますが、_\r\n_(Windowsに保存されたファイルから)で作成することもできます。

ソリューション

1。 componentsSeparatedByCharactersInSet

_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つの文字としてカウントされ、文字列を同じ場所で2回区切るため、空の配列要素が生成されます。

2。 split

_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_は1つのSwift文字(拡張書記素クラスタ)としてカウントされます)

3。 enumerateLines

_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_を含みます。
  • この回答は 私の前の質問 に対する回答の要約です。詳細については、これらの回答をお読みください。
7
Suragch
let test1 = "Line1\n\rLine2\nLine3\rLine4"
let t1 = test1.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
let t2 = t1.filter{ $0 != "" }
let t3 = t1.filter{ !$0.isEmpty }
6
user3441734

記録として、スウィフトの財団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)
    }
}
3
Cœur

空の要素のない文字列配列を取得するには、どのように文字列を改行で分割しますか?

あなたはほとんどそこにいました-ここで異なるのは単に末尾のクロージャです:

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:末尾のクロージャーで不要な余分なブラケットを削除

1
simons

Swift 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つの項目の配列ができました。

["Line1"、 "Line2"、 "Line3"]

私はCSVファイルを使用していますが、これを行った後、アイテムをコンポーネントに分割しています。

["Line1、Line2、Line3"、 "LineA、LineB、LineC"]

        let component0 = csvStrings[0].components(separatedBy: [","]) // ["Line1","Line2","Line3"]
        let component1 = csvStrings[1].components(separatedBy: [","]) // ["LineA","LineB","LineC"]
1
Alan Gonzalez
     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
0
Davender Verma