String 如何在Swift中进行字符串编程

String 如何在Swift中进行字符串编程,string,unicode,swift,String,Unicode,Swift,我错过了可用的字符串函数,这些函数很容易使用,无需键入奇怪的标识符行。所以我决定建立一个包含有用且可识别的字符串函数的库。我首先尝试使用Cocoa字符串函数来解决这个问题。所以我在操场上试着: import Cocoa func PartOfString(s: String, start: Int, length: Int) -> String { return s.substringFromIndex(advance(s.startIndex, start - 1)).subs

我错过了可用的字符串函数,这些函数很容易使用,无需键入奇怪的标识符行。所以我决定建立一个包含有用且可识别的字符串函数的库。

我首先尝试使用Cocoa字符串函数来解决这个问题。所以我在操场上试着:

import Cocoa

func PartOfString(s: String, start: Int, length: Int) -> String
{
    return s.substringFromIndex(advance(s.startIndex, start - 1)).substringToIndex(advance(s.startIndex, length))
}

PartOfString("HelloaouAOUs.World", 1, 5) --> "Hello"
PartOfString("HelloäöüÄÖÜß…World", 1, 5) --> "Hello"

PartOfString("HelloaouAOUs.World", 1, 18) --> "HelloaouAOUs.World"
PartOfString("HelloäöüÄÖÜß…World", 1, 18) --> "HelloäöüÄÖÜß…World"

PartOfString("HelloaouAOUs.World", 6, 7) --> "aouAOUs"
PartOfString("HelloäöüÄÖÜß…World", 6, 7) --> "äöüÄO"
如果大小写的字符串中包含未编码字符,则substringFromIndex不是起始索引。更糟糕的是,Swift程序有时在运行时崩溃,如果字符串中包含未编码的字符,那么substringFromIndex不是起始索引。所以我决定创建一组新函数,处理这个问题并处理未编码字符。请注意,文件名也可以包含未编码字符。因此,如果您认为不需要非编码字符,那么您就错了

如果你想复制这个,你需要和我使用的相同的字符串,因为从这个网页复制不会复制这个问题

var s: String = "HelloäöüÄÖÜß…World"
var t: String = s.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
var u: String = "Helloa%CC%88o%CC%88u%CC%88A%CC%88O%CC%88U%CC%88%C3%9F%E2%80%A6World".stringByRemovingPercentEncoding!
var b: Bool = (s == u) --> true
PartOfString(s, 6, 7) --> "äöüÄO"
现在,您可以使用以下函数将令人不安的规范映射Unicode转换为兼容的Unicode:

func percentescapesremove (s: String) -> String
{
    return (s.stringByRemovingPercentEncoding!.precomposedStringWithCompatibilityMapping)
}
您将得到的结果是:

var v: String = percentescapesremove(t) --> "HelloäöüÄÖÜß...World"
PartOfString(v, 6, 7) --> "äöüÄÖÜß"
var a: Bool = (s == v) --> false
当你这么做的时候,你会觉得这件衣服看起来不错,你会想,一切都好,但看看。。。已从UniCode…永久转换为非UniCode。。。并具有与第一个字符串不同的结果。如果您有UniCode文件名,则转换将导致在卷上找不到该文件。因此,最好只为scree输出进行转换,并将原始字符串保存在保存位置

上面的PartOfString函数的问题是,它在赋值的第一部分生成一个新字符串,并将这个新字符串与旧字符串的索引一起使用,这不起作用,因为Unicode的长度与普通字母不同。所以我改进了功能,感谢Martin R的帮助:

func NewPartOfString(s: String, start: Int, length: Int) -> String
{
    let t: String = s.substringFromIndex(advance(s.startIndex, start - 1))
    return t.substringToIndex(advance(t.startIndex, length))
}
结果是正确的:

NewPartOfString("HelloaouAOUs.World", 1, 5) --> "Hello"
NewPartOfString("HelloäöüÄÖÜß…World", 1, 5) --> "Hello"

NewPartOfString("HelloaouAOUs.World", 1, 18) --> "HelloaouAOUs.World"
NewPartOfString("HelloäöüÄÖÜß…World", 1, 18) --> "HelloäöüÄÖÜß…World"

NewPartOfString("HelloaouAOUs.World", 6, 7) --> "aouAOUs"
NewPartOfString("HelloäöüÄÖÜß…World", 6, 7) --> "äöüÄÖÜß"
在下一步中,我将展示一些可以使用且工作良好的函数。所有这些都基于整数索引值,第一个字符的结尾从1开始,最后一个字符的索引与字符串的长度相同

此函数返回字符串的长度:

func len (s: String) -> Int
{
    return (countElements(s)) // This works not really fast, because of UniCode
}
此函数用于返回字符串中第一个UniCode字符的UniCode编号:

func asc (s: String) -> Int
{
    if (s == "")
    {
        return 0
    }
    else
    {
        return (Int(s.unicodeScalars[s.unicodeScalars.startIndex].value))
    }
}
此函数用于返回给定UniCode数字的UniCode字符:

func char (c: Int) -> String
{
    var s: String = String(UnicodeScalar(c))
    return (s)
}
此函数返回字符串的大写表示形式:

func ucase (s: String) -> String
{
    return (s.uppercaseString)
}
func lcase (s: String) -> String
{
    return (s.lowercaseString)
}
func val (s: String) -> Int
{
    var p: Int = 0
    var sign: Int = 0

    if (indchar(s, 1) == "-")
    {
        sign = 1
        p = 1
    }
    while(number(asc(indchar(s, p + 1))))
    {
        p = p + 1
    }
    if (p > sign)
    {
        return (left(s, p).toInt()!)
    }
    else
    {
        return (0)
    }
}
此函数返回字符串的小写表示形式:

func ucase (s: String) -> String
{
    return (s.uppercaseString)
}
func lcase (s: String) -> String
{
    return (s.lowercaseString)
}
func val (s: String) -> Int
{
    var p: Int = 0
    var sign: Int = 0

    if (indchar(s, 1) == "-")
    {
        sign = 1
        p = 1
    }
    while(number(asc(indchar(s, p + 1))))
    {
        p = p + 1
    }
    if (p > sign)
    {
        return (left(s, p).toInt()!)
    }
    else
    {
        return (0)
    }
}
下一个函数给出具有给定长度的字符串的左侧部分:

func left (s: String, length: Int) -> String
{
    if (length < 1)
    {
        return ("")
    }
    else
    {
        if (length > len(s))
        {
            return (s)
        }
        else
        {
            return (s.substringToIndex(advance(s.startIndex, length)))
        }
    }
}
func right (s: String, laenge: Int) -> String
{
    var L: Int = len(s)
    if (L <= laenge)
    {
        return(s)
    }
    else
    {
        if (laenge < 1)
        {
            return ("")
        }
        else
        {
            let t: String = s.substringFromIndex(advance(s.startIndex, L - laenge))
            return t.substringToIndex(advance(t.startIndex, laenge))
        }
    }
}
func mid (s: String, start: Int, laenge: Int) -> String
{
    if (start <= 1)
    {
        return (left(s, laenge))
    }
    else
    {
        var L: Int = len(s)
        if ((start > L) || (laenge < 1))
        {
            return ("")
        }
        else
        {
            if (start + laenge > L)
            {
                let t: String = s.substringFromIndex(advance(s.startIndex, start - 1))
                return t.substringToIndex(advance(t.startIndex, L - start + 1))
            }
            else
            {
                let t: String = s.substringFromIndex(advance(s.startIndex, start - 1))
                return t.substringToIndex(advance(t.startIndex, laenge))
            }
        }
    }
}
func substring(s: String, Start: Int, Length: Int) -> String
{
    var L: Int = len(s)
    var UniCode = Array(s)
    var result: String = ""
    var TheEnd: Int = Start + Length - 1

    if ((Start < 1) || (Start > L))
    {
        return ("")
    }
    else
    {
        if ((Length < 0) || (TheEnd > L))
        {
            TheEnd = L
        }
        for var i: Int = Start; i <= TheEnd; ++i
        {
            result = result + String(UniCode[i - 1])
        }
        return (result)
    }
}
因此我们看到,结果字符串太短,因为UniCode字符可以包含多个字符。这是因为ä可以是一个UniCode字符,也可以写成两个a–UniCode字符。所以我们需要另一种方法来获得有效的子字符串

func CharacterOfString(s: String, index: Int, length: Int) -> String
{
    var c: String = ""
    var i: Int = 0
    for UniCodeChar in s.unicodeScalars
    {
        i = i + 1
        if ((i >= index) && (i < index + length))
        {
            c = c + String(UniCodeChar)
        }
    }
    return (c)
}
解决方案是,将UniCode字符串转换为UniCode字符数组,并使用数组的索引获取有效字符。这在任何情况下都适用于在给定索引处获取UniCode字符串的单个字符:

func indchar (s: String, i: Int) -> String
{
    if ((i < 1) || (i > len(s)))
    {
        return ("")
    }
    else
    {
        return String(Array(s)[i - 1])
    }
}
如果给定的字符代码是数字0-9,则此函数将显示:

func number (n: Int) -> Bool
{
    return ((n >= 48) & (n <= 57)) // "0" to "9"
}
但如果字符串包含某些字符,则此操作无效:

var s: String = "123." --> "123."
var v: Int = s.toInt()! --> Will result in a Runtime Error, because s.toInt() = nil
所以我决定构建一个smater函数来获取字符串的值:

func ucase (s: String) -> String
{
    return (s.uppercaseString)
}
func lcase (s: String) -> String
{
    return (s.lowercaseString)
}
func val (s: String) -> Int
{
    var p: Int = 0
    var sign: Int = 0

    if (indchar(s, 1) == "-")
    {
        sign = 1
        p = 1
    }
    while(number(asc(indchar(s, p + 1))))
    {
        p = p + 1
    }
    if (p > sign)
    {
        return (left(s, p).toInt()!)
    }
    else
    {
        return (0)
    }
}
现在,结果是正确的,不会产生运行时错误:

var s: String = "123." --> "123."
var v: Int = val(s) --> 123
现在浮点数也是一样的:

func realval (s: String) -> Double
{
    var r: Double = 0
    var p: Int = 1
    var a: Int = asc(indchar(s, p))
    if (indchar(s, 1) == "-")
    {
        p = 2
    }
    while ((a != 44) && (a != 46) && ((a >= 48) & (a <= 57)))
    {
        p = p + 1
        a = asc(indchar(s, p))
    }
    if (p >= len(s)) // Integer Number
    {
        r = Double(val(s))
    }
    else // Number with fractional part
    {
        var mantissa: Int = val(substring(s, p + 1, -1))
        var fract: Double = 0
        while (mantissa != 0)
        {
            fract = (fract / 10) + (Double(mantissa % 10) / 10)
            mantissa = mantissa / 10
            p = p + 1
        }
        r = Double(val(s)) + fract
        p = p + 1
    }
    a = asc(indchar(s, p))
    if ((a == 69) || (a == 101)) // Exponent
    {
        var exp: Int = val(substring(s, p + 1, -1))
        if (exp != 0)
        {
            for var i: Int = 1; i <= abs(exp); ++i
            {
                if (exp > 0)
                {
                    r = r * 10
                }
                else
                {
                    r = r / 10
                }
            }
        }
    }
    return (r)
}
从整数生成字符串要简单得多:

func str (n: Int) -> String
{
    return (String(n))
}
浮点变量的字符串不适用于Stringn,但可以通过以下方式完成:

func strreal (n: Double) -> String
{
    return ("\(n)")
}

我建议大家阅读语言规范+1的这一章,了解问题和答案,以便从原来的帖子中分离出来。欢迎来到StackOverflow@尼科拉:这就是我所做的,但这需要很多时间。这篇文章是为所有新来者准备的,他们希望不用几个小时的阅读就能轻松地用字符串和快捷的方式做一些事情。当你通读我的答案,并会发现一些事情,可以做得更容易,比请留下评论。谢谢。我无法复制你关于PrintlPartofStringHelloäöü196;ÜÜÜÜ…World,6,7的初始声明,它在我的应用程序中返回正确的结果。但是仅仅为了提取一个子字符串或单个字符而创建一个字符串的所有字符的数组对于非常长的字符串来说是非常低效的。我还怀疑是否值得重新编程转换为int或实值。如果您不喜欢toInt的严格行为,那么您仍然可以使用Cocoa中的intValue/doubleValue,例如,让i=s作为NSString.doubleValue。我使用UniCode字符串Hello%C3%A4%C3%B6%C3%BC%C3%84%C3%96%C3%9C%C3%9F…World。当从这个网页复制它时,它可以工作,但不是原始的。原因是相同光学外观的不同编码。如果要复制此内容,请使用:PartOfStringHello%C3%A4%C3%B6%C
3%BC%C3%84%C3%96%C3%9C%C3%9F…世界。stringByRemovingPercentEncoding!。分解的StringWithCanonicalMapping,6,8如果您使用substringWithRange,就像在这个问题的一些答案中一样,它似乎工作正常:让startIndex=advances.startIndex,start-1;设endIndex=AdvancesStartIndex,长度;return=s.substringWithRangestartIndex..