Arrays 从包含某些(双)字符的字符串创建字符串数组

Arrays 从包含某些(双)字符的字符串创建字符串数组,arrays,swift,string,Arrays,Swift,String,我有一串单词和数学/编程使用的符号。例如,类似这样的内容: var source = "a + b + 3 == c" let symbols = ["+", "-", "==", "!="] var results: [Substring] = [] for symbol in symbols { var startIndex = source.startIndex var

我有一串单词和数学/编程使用的符号。例如,类似这样的内容:

var source = "a + b + 3 == c"
let symbols = ["+", "-", "==", "!="]

var results: [Substring] = []

for symbol in symbols {
    var startIndex = source.startIndex
    var ranges: [Range<String.Index>] = []
    while startIndex < source.endIndex,
          let range = source[startIndex...].range(of: symbol) {
        ranges.append(range)
        results.append(source[range])
        startIndex = source.index(after: range.upperBound)
    }
    for range in ranges.reversed() {
        source.removeSubrange(range)
    }
}

print(results)  
let source=“a+b+3==c”
(注意:不能依赖空格)

我还有一个字符串数组,需要从源字符串中筛选出来:

让符号=[“+”、“-”、“==”、“!=”]
现在,我需要创建一个匹配项的数组(带有重复项)。在这种情况下,这将是
[“+”,“+”,“==”]

根据我的尝试,
==
是两个字符,因此我无法执行以下操作:

let source=“a+b+3==c”
让符号=字符集(字符集:+-=≠") // 不是“==”和“!=”,而是“=”和“≠' 因为它是一个字符集
让操作=源
.map{String($0)}
.filter{symbols.contains中的字符(UnicodeScalar(char)!)}
打印(操作)
//输出:[“+”、“+”、“=”、“=”]
//需要:[“+”、“+”、“=”]

非常感谢您提供的任何帮助

您需要的是将您的符号作为常规字符串进行威胁。迭代每个符号并在源代码中进行搜索。如果您找到一个范围,请将其附加到集合中,在该位置获取子字符串,然后从范围上限后的索引中再次搜索字符串。当您到达字符串搜索的结尾时对于该符号,请从源代码中删除子字符串。请尝试以下操作:

var source = "a + b + 3 == c"
let symbols = ["+", "-", "==", "!="]

var results: [Substring] = []

for symbol in symbols {
    var startIndex = source.startIndex
    var ranges: [Range<String.Index>] = []
    while startIndex < source.endIndex,
          let range = source[startIndex...].range(of: symbol) {
        ranges.append(range)
        results.append(source[range])
        startIndex = source.index(after: range.upperBound)
    }
    for range in ranges.reversed() {
        source.removeSubrange(range)
    }
}

print(results)  
var source=“a+b+3==c”
让符号=[“+”、“-”、“==”、“!=”]
变量结果:[子字符串]=[]
对于符号中的符号{
var startIndex=source.startIndex
变量范围:[范围]=[]
而startIndex
这会打印出来

[“+”、“+”、“=”]


这个问题是一个解析问题,就是将输入字符串转换成某种结构化数据。一个很好的方法是使用解析器组合器。虽然这个问题很复杂,但一旦设置好,示例“opStrings”函数就很容易理解,也很容易扩展

struct Parser<A> {
    let run: (inout Substring) -> A?

    static func always<A>(_ a: A) -> Parser<A> {
        .init { _ in a }
    }

    static var never: Parser {
        .init { _ in nil }
    }

    func map<B>(_ f: @escaping (A) -> B) -> Parser<B> {
        Parser<B> { str -> B? in
            self.run(&str).map(f)
        }
    }
    
    func flatMap<B>(_ f: @escaping (A) -> Parser<B>) -> Parser<B> {
        Parser<B> { str -> B? in
            let original = str
            let matchA = self.run(&str)
            let parserB = matchA.map(f)
            guard let matchB = parserB?.run(&str) else {
                str = original
                return nil
            }
            return matchB
        }
    }

    func run(_ str: String) -> (match: A?, rest: Substring) {
        var str = str[...]
        let match = self.run(&str)
        return (match, str)
    }
}

func prefix(while p: @escaping (Character) -> Bool) -> Parser<Substring> {
    Parser<Substring> { str in
        let prefix = str.prefix(while: p)
        str.removeFirst(prefix.count)
        return prefix
    }
}

func literalString(_ p: String) -> Parser<String?> {
    Parser<String?> { str in
        guard str.hasPrefix(p) else { return nil }
        str.removeFirst(p.count)
        return p
    }
}

func literal(_ str: String) -> Parser<Void> {
    literalString(str).map {
        _ in ()
    }
}

func oneOrMore<A>(_ predicate: @escaping (Character) -> Bool,
                 mapped f: @escaping (Substring) -> A) -> Parser<A> {
    prefix(while: predicate)
        .flatMap { $0.isEmpty ? .never : .always(f($0)) }
}

let oneOrMoreDecimals = oneOrMore((\.isNumber), mapped: Double.init)
    .flatMap { d -> Parser<Double> in
        guard let d = d else { return .never }
        return .always(d)
    }

func oneOf<A>(_ ps: [Parser<A>]) -> Parser<A> {
    Parser<A> { str -> A? in
        for p in ps {
            if let match = p.run(&str) {
                return match
            }
        }
        return nil
    }
}

let whitespace = oneOf([
        literal(" "),
        literal("\t"),
        literal("\n")
    ])

let identifier = prefix(while: { ($0.isLetter && $0.isASCII) || $0.isNumber })
    .flatMap { str -> Parser<String> in
    guard let first = str.first else { return Parser.never }
        return first.isNumber ? .never : .always(String(str))
}

let literalNumber = prefix(while: { $0.isNumber })
    .flatMap { str -> Parser<Double> in
        guard let value = Double(str) else { return Parser.never }
        return .always(value)
    }

func skip<T, U>(_ p: Parser<T>) -> Parser<U?> {
    p.map { _ in nil }
}

struct Example {
    enum Token {
        case minus
        case plus
        case equal
        case equalEqual
        case notEqual
        case identifier(String)
        case number(Double)
    }

    enum Error: Swift.Error {
        case unexpectedInput
    }
    
    let input: String

    func run<T>(_ parsers: [Parser<T?>]) throws -> [T] {
        var source = Substring(input)
        var results: [T] = []
        
        while let token = oneOf(parsers).run(&source) {
            if let token = token {
                results.append(token)
            }
        }
        
        guard source.isEmpty else {
            throw Error.unexpectedInput
        }
        
        return results
    }
    
    func tokenize() throws -> [Token] {
        let tokenizers: [Parser<Token?>] = [
            literal("-").map { .minus },
            literal("+").map { .plus },
            literal("==").map { .equalEqual },
            literal("!=").map { .notEqual },
            literal("=").map { .equal },
            identifier.map { .identifier($0) },
            oneOrMoreDecimals.map { .number($0) },
            skip(whitespace)
        ]
        
        return try run(tokenizers)
    }
    
    func opStrings() throws -> [String] {
        try run([
            literalString("-"),
            literalString("+"),
            literalString("=="),
            literalString("!="),
            literalString("="),
            skip(identifier),
            skip(oneOrMoreDecimals),
            skip(whitespace),
        ] as [Parser<String?>])
    }
}

do {
    let example = Example(input: "a + b + 3 == c")
    // let tokens = try example.tokenize()
    print(try example.opStrings()) // ["+", "+", "=="]
}
catch {
    print(error)
}
struct解析器{
让我们运行:(inout子字符串)->A?
静态func始终(a:a)->解析器{
.init{in a}
}
静态变量:解析器{
.init{in nil}
}
func映射(f:@escaping(A)->B)->解析器{
解析器{str->B?in
self.run(&str).map(f)
}
}
func平面映射(f:@escaping(A)->Parser)->Parser{
解析器{str->B?in
让原始=str
让matchA=self.run(&str)
让parserB=matchA.map(f)
guard let matchB=parserB?.run(&str)else{
str=原件
归零
}
返回匹配B
}
}
func run(str:String)->(匹配:A?,其余:子字符串){
var str=str[…]
让match=self.run(&str)
返回(匹配,str)
}
}
func前缀(而p:@escaping(Character)->Bool)->解析器{
解析器{str in
let prefix=str.prefix(while:p)
str.removeFirst(前缀.count)
返回前缀
}
}
func literalString(p:String)->解析器{
解析器{str in
guard str.hasPrefix(p)else{return nil}
str.removeFirst(p.count)
返回p
}
}
func literal(str:String)->解析器{
literalString(str).map{
_在()
}
}
func oneOrMore(u谓词:@escaping(Character)->Bool,
映射f:@escaping(子字符串)->A)->Parser{
前缀(while:predicate)
.flatMap{$0.isEmpty?.never:.always(f($0))}
}
设oneOrMoreDecimals=oneOrMore(\.isNumber),映射为:Double.init)
.flatMap{d->中的解析器
guard let d=d else{return.never}
返回。始终(d)
}
func oneOf(ps:[解析器])->Parser{
解析器{str->A?in
对于ps中的p{
如果let match=p.run(&str){
复赛
}
}
归零
}
}
让空白=其中一个([
文字(“”),
文字(“\t”),
文字(“\n”)
])
let identifier=前缀(while:{($0.isleter&&$0.isASCII)| |$0.isNumber})
.flatMap{str->中的解析器
guard let first=str.first-else{return Parser.never}
返回first.isNumber?.never:。始终(字符串(str))
}
让literalNumber=前缀(while:{$0.isNumber})
.flatMap{str->中的解析器
guard let value=Double(str)else{return Parser.never}
return.always(值)
}
func skip(p:Parser)->Parser{
p、 映射{uu}in nil}
}
结构示例{
枚举令牌{
减号
案例加号
大小写相等
格相等
案例说明
案例标识符(字符串)
案件编号(双)
}
枚举错误:Swift.Error{
未预料到的情况
}
让输入:字符串
func run(parsers:[Parser])抛出->[T]{
变量源=子字符串(输入)
var结果:[T]=[]
而let token=one/of(解析器)。运行(&source){
如果let token=token{
results.append(标记)
}
}
我没有别的了{
抛出错误
}
返回结果
}
func tokenize()抛出->[Token]{
让标记器:[解析器]=[
文字(“-”).map{.减号},
文字(“+”).map{.plus},
文字(“=”).map{.equalEqual},
文字(“!=”).map{.notEqual},
文字(“=”).map{.equal},
identifier.map{.identifier($0)},
oneOrMoreDecimals.map{.number($0)},
跳过(空白)