2016-07-11 3 views
-1

Swift文字列から最大255個のUTF8コード単位の有効な部分文字列を取得しようとしています(データベースVARCHAR(255)フィールドを格納できるという考えです)。データベース内のスウィフト文字列を合わせるVARCHAR(255)

部分文字列を取得する標準的な方法はこれです:

let string: String = "Hello world!" 
let startIndex = string.startIndex 
let endIndex = string.startIndex.advancedBy(255, limit: string.endIndex) 
let databaseSubstring1 = string[startIndex..<endIndex] 

しかし、明らかにそれは私のUTF8表現に255を超えるバイトが必要な場合があり、255文字の文字列を与えるだろう。

UTF8のために私はこれを書くことができます:

let utf8StartIndex = string.utf8.startIndex 
let utf8EndIndex = utf8StartIndex.advancedBy(255, limit: string.utf8.endIndex) 
let databaseSubstringUTF8View = name.utf8[utf8StartIndex..<utf8EndIndex] 
let databaseSubstring2 = String(databaseSubstringUTF8View) 

しかし、私は私のUTF8Viewが有効なUTF8シーケンスではないでしょう意味末尾の半分の文字を、持つことのリスクを実行します。 そして、databaseSubstring2は、イニシャライザが失敗する可能性がある(public init?(_ utf8: String.UTF8View)と定義されているため)オプションの文字列です。

最後に無効なUTF8コードポイントを取り除く方法が必要です。可能であれば、私がここでやろうとしていることをやり遂げる方法が必要です。

EDIT

は、データベースが文字を理解していることが判明したので、私はUTF8コード単位をカウントしようとしてはならないのではなく、データベースは(おそらく、データベースに依存します)私の文字列にカウントされますどのように多くの文字。

@OOPerによると、MySQLは文字をUTF-16コード単位としてカウントします。アイデアは(つまり、スウィフトが文字が何であるかを考えるものです)UTF-16コード単位を数えるが、最後から文字を削除することです

private func databaseStringForString(string: String, maxLength: Int = 255) -> String 
{ 
    // Start by clipping to 255 characters 
    let startIndex = string.startIndex 
    let endIndex = startIndex.advancedBy(maxLength, limit: string.endIndex) 
    var string = string[startIndex..<endIndex] 

    // Remove characters from the end one by one until we have less than 
    // the maximum number of UTF-16 code units 
    while (string.utf16.count > maxLength) { 
     let startIndex = string.startIndex 
     let endIndex = string.endIndex.advancedBy(-1, limit: startIndex) 
     string = string[startIndex..<endIndex] 
    } 
    return string 
} 

:私は、次の実装が出ています。

EDIT 2

それでも@OOPerによると、Posgresqlは、Unicodeスカラーなどの文字を数えるので、これはおそらく動作するはずです:私は私のコメントで書いたよう

private func databaseStringForString(string: String, maxLength: Int = 255) -> String 
{ 
    // Start by clipping to 255 characters 
    let startIndex = string.startIndex 
    let endIndex = startIndex.advancedBy(maxLength, limit: string.endIndex) 
    var string = string[startIndex..<endIndex] 

    // Remove characters from the end one by one until we have less than 
    // the maximum number of Unicode Scalars 
    while (string.unicodeScalars.count > maxLength) { 
     let startIndex = string.startIndex 
     let endIndex = string.endIndex.advancedBy(-1, limit: startIndex) 
     string = string[startIndex..<endIndex] 
    } 
    return string 
} 
+0

を私は混乱している...あなたは結果が255 *文字になりたいん*、または255 *バイト*? – deceze

+0

結果を 'VARCHAR(255)'に格納したいので、最大255バイトです。しかし、私は有効なUTF8シーケンスが欲しいので、それを少なくする必要があります。 – deadbeef

+0

あなたはどのデータベースを使用していますか? MySQLの 'VARCHAR(255)'は、列のエンコーディングで255 *文字*を意味します。これは255バイトを超えることがあります。 – deceze

答えて

1

は、あなたがあなたのdatabaseStringForString(_:maxLength:)が必要な場合がありますDBMSの長さ制限に合わせて文字列を切り捨てます。 PostgreSQL(utf8)、MySQL(utf8mb4)。

そして、私はあなたのEDIT 2と同じ機能を記述します。

func databaseStringForString(string: String, maxUnicodeScalarLength: Int = 255) -> String { 
    let start = string.startIndex 
    for index in start..<string.endIndex { 
     if string[start..<index.successor()].unicodeScalars.count > maxUnicodeScalarLength { 
      return string[start..<index] 
     } 
    } 
    return string 
} 

これはあまり効率的ではなく、少し短くなることがあります。

let s = "abc\u{1D122}\u{1F1EF}\u{1F1F5}" //->"abc" 

let dbus = databaseStringForString(s, maxUnicodeScalarLength: 5) //->"abc"(=="abc\u{1D122}") 

ので、UTF8でのMySQLで動作します誰か(= utf8mb3)はこのような何か必要があります:

func databaseStringForString(string: String, maxUTF16Length: Int = 255) -> String { 
    let start = string.startIndex 
    for index in start..<string.endIndex { 
     if string[start..<index.successor()].utf16.count > maxUTF16Length { 
      return string[start..<index] 
     } 
    } 
    return string 
} 

let dbu16 = databaseStringForString(s, maxUTF16Length: 4) //->"abc" 
+0

ありがとうございます。これはかなりうまくいくようです。 SwiftとPostgreSQLが同じUnicodeスカラーの定義を持つことを望みましょう。 Swiftはこれを使用しているようです:http://www.unicode.org/glossary/#unicode_scalar_value – deadbeef

関連する問題