
[ad_1]
Validando a entrada do usuário sem a nova sintaxe Regex
Você pode rastrear a história do Regex até um matemático americano, Stephen Cole Kleene, que propôs a ideia de texto representando padrões usando expressões matemáticas de tipos em 1951. No entanto, seu trabalho não decolou até que Ken Thompson decidiu usá-lo em seu editores QED e ED em 1967, rodando em UNIX, o precursor do OSX, iOS e Android.
Embora você possa argumentar que a brevidade das expressões Regex quase certamente influenciou a sintaxe de uma das linguagens de programação mais populares do mundo, ou seja, C, que não foi lançada até 1972. Um precursor do Objective C e agora do Swift.
Embora o Regex não tenha encontrado seu caminho para a linguagem C, ele foi incorporado a dezenas de utilitários do UNIX, como grep, awk e vi — e às linguagens de programação mais modernas. Então, é um tanto surpreendente [at least for me] que levou quase quarenta anos para a Apple adotar Regex em Objective C, esperando até 2010.
E outra década antes, eles tentaram atualizá-lo na WWDC2022, reescrevendo a sintaxe para torná-la mais amigável. Junte-se a mim na tentativa de atualizar este artigo e seus pares com algumas Regex mais modernas. Embora eu use a sintaxe original dentro da nova estrutura de comando em grande parte.
Antes de começar, quero definir 12 regras com a sintaxe Regex que irei corresponder. Como eu disse, a sintaxe aqui é quase a mesma de 1967, portanto — bem estabelecida.
enum Rules:String, CaseIterable {
case alphaRule = "[A-Za-z]+"
case digitRule = "[0-9]+"
case limitedAlphaNumericCombined = "[A-Za-z0-9]{4,12}"
case limitedAlphaNumericSplit = "[A-Za-z]{4,12}[0-9]{2,4}"
case currencyRule = "(\\w*)[£$€]+(\\w*)"
case wordRule = "(\\w+)"
case numericRule = "(\\d+)"
case numberFirst = "^(\\d+)(\\w*)"
case numberLast = "(\\w*)(\\d+)$"
case spaceRule = "[\\S]"
case capitalFirst = "^[A-Z]+[A-Za-z]*"
case punctuationCharacters = "[:punct:]"
}
Em resumo, colchetes significam caracteres no intervalo indicado; um sinal de mais significa um ou mais. Os números entre colchetes são uma contagem mínima e máxima de caracteres. A barra dupla seguida de uma letra minúscula é uma classe de caracteres, e a barra dupla seguida de uma letra maiúscula é o inverso dessa classe. Um asterisco significa zero ou mais. O significado do chapéu deve começar com o seguinte caractere se estiver fora dos colchetes.
Cuidado com o chapéu também significa o inverso se estiver dentro dos colchetes. O dólar significa deve terminar com o referido padrão. E, finalmente, você tem uma classe POSIX [:punct:]
Que é auto-explicativo.
Com um conjunto de mensagens de erro vinculadas [in the same order] ao referido Regex.
enum Crips:String, CaseIterable {
case alphaRule = "MUST be alpha only"
case digitRule = "MUST be numeric ONLY"
case limitRuleCombined = "MIN 4 AlphaNumeric MAX 12 AlphaNumeric"
case limitRuleSplit = "START MIN 4 Alpha MAX 12 Alpha, FINISH MIN 2 numeric, MAX 4 numeric"
case currencyRule = "MUST contain $£€"
case wordRule = "MUST be alphanumeric"
case numericRule = "MUST be numeric"
case numberFirst = "MUST start with a number"
case numberLast = "MUST finish with a number"
case noSpaces = "MUST not contain spaces or tabs"
case leadingCapital = "MUST start with am uppercase letter"
case punctuationCharacters = "MUST contain punctuation characters"static var cripList: [String] {
return Crips.allCases.map { $0.rawValue }
}
}
Mas, antes de começar, aqui está uma extensão que usei para me ajudar a mapear o primeiro conjunto de enums para o segundo. Ele retorna o índice do enum submetido a ele.
extension CaseIterable where Self: Equatable {
public func ordinal() -> Self.AllCases.Index {
return Self.allCases.firstIndex(of: self)!
}
}
Logo em seguida – para o prato principal. Eu quero mantê-lo o mais simples possível. Começo definindo uma estrutura dentro da qual usarei as mensagens vinculadas às expressões regex que não correspondem à minha string de senha.
struct Diag: Hashable, Codable, Identifiable {
var id = UUID()
var message = ""
}
Uma estrutura que eu faço Hashable
, Codable
e Identifiable
para que eu possa usá-lo em um loop SwiftUI. Agora, ao prato principal, dentro do qual tenho duas funções principais. A primeira aqui é corresponder às expressões Regex em minha enumeração.
fileprivate func matchRegex() {
for rule in Rules.allCases {
let formulae = try! Regex(rule.rawValue)
if let _ = passText.wholeMatch(of: formulae) {
// is good, right size alpha upper + lower & numeric
} else {
let diag = Crips.cripList[rule.ordinal()]
diagMsgs.append(Diag(message: "\(diag)"))
let foo = /\a/
print(foo)
}
}
}
Ele percorre todo o Regex em meus conjuntos. Construindo uma matriz enquanto faz isso de mensagens de diagnóstico para todas as correspondências com falha.
Agora, a segunda função exibe uma lista de diagnósticos semelhante a um console que rolará para fora da tela se ficar muito grande.
fileprivate func displaceFailedMatches() -> ScrollViewReader<ScrollView<VStack<some View>>> {
return ScrollViewReader { moveTo in
ScrollView(.vertical) {
VStack(alignment: .leading) {
ForEach(diagMsgs, id: \.id) { text in
Text("\(text.message)")
.font(Fonts.neutonRegular(size: 16))
.id(text.id)
}.onChange(of: diagMsgs) { _ in
moveTo.scrollTo(diagMsgs.last?.id, anchor: .bottom)
}
}
}
}
}
Finalmente, tenho o corpo principal.
var body: some View {
VStack {
HStack {
Spacer(minLength: 4)
TextField("Pass ", text: $passText)
.font(Fonts.neutonRegular(size: 32)).onChange(of: passText) { newValue in
diagMsgs.removeAll()
matchRegex()
if passText.isEmpty {
diagMsgs.removeAll()
}
}
.border(Color.black)
.padding(.top, 64)
Spacer()
}
displaceFailedMatches()
}
}
Um corpo que você precisa definir com as variáveis de dois estados mostradas, referenciadas nos métodos já mencionados.
struct ContentView: View {
@State var passText = ""
@State var diagMsgs:[Diag] = []
Juntando tudo, você obtém um campo na parte superior da tela onde você insere uma palavra. Uma palavra foi testada contra todas as Regexes do array, relatando as correspondências com falha.
Como você vê, é impossível limpar todas as mensagens de erro, pois tenho conjuntos conflitantes. Deixo para o leitor descobrir quais eles precisam suprimir para obter alguns conjuntos de trabalho.
Tudo isso me leva ao final deste pequeno artigo. Reserve um momento para assistir aos vídeos do WWDC2022 sobre o assunto se estiver interessado em saber mais. A Apple desenvolveu uma nova sintaxe para expressões Regex, embora eu alerte o leitor de que talvez eles devam aprender primeiro a versão que existe há sessenta anos ou mais [shown in this paper].
É o sabor do Regex que você encontrará em qualquer outro lugar.
[ad_2]
Source link