A delightful and expressive regular expression type for Swift.

Related tags

Regex Regex
Overview

Regex

Pattern match like a boss.

Usage

Create:

// Use `Regex.init(_:)` to build a regex from a static pattern

let greeting = Regex("hello (world|universe)")

// Use `Regex.init(string:)` to construct a regex from dynamic data, and
// gracefully handle invalid input

var validations: [String: Regex]

for (name, pattern) in config.loadValidations() {
  do {
    validations[name] = try Regex(string: pattern)
  } catch {
    print("error building validation \(name): \(error)")
  }
}

Match:

if greeting.matches("hello universe!") {
  print("wow, you're friendly!")
}

Pattern match:

switch someTextFromTheInternet {
case Regex("DROP DATABASE (.+)"):
  // TODO: patch security hole
default:
  break
}

Capture:

let greeting = Regex("hello (world|universe|swift)")

if let subject = greeting.firstMatch(in: "hello swift")?.captures[0] {
  print("ohai \(subject)")
}

Find and replace:

"hello world".replacingFirst(matching: "h(ello) (\\w+)", with: "H$1, $2!")
// "Hello, world!"

Accessing the last match:

switch text {
case Regex("hello (\\w+)"):
  if let friend = Regex.lastMatch?.captures[0] {
    print("lovely to meet you, \(friend)!")
  }
case Regex("goodbye (\\w+)"):
  if let traitor = Regex.lastMatch?.captures[0] {
    print("so sorry to see you go, \(traitor)!")
  }
default:
  break
}

Options:

let totallyUniqueExamples = Regex("^(hello|foo).*$", options: [.ignoreCase, .anchorsMatchLines])
let multilineText = "hello world\ngoodbye world\nFOOBAR\n"
let matchingLines = totallyUniqueExamples.allMatches(in: multilineText).map { $0.matchedString }
// ["hello world", "FOOBAR"]

Decode:

let json = """
  [
    {
      "name" : "greeting",
      "pattern" : "^(\\\\w+) world!$"
    }
  ]
  """.data(using: .utf8)!

struct Validation: Codable {
  var name: String
  var pattern: Regex
}

let decoder = JSONDecoder()
try decoder.decode(Validation.self, from: json)
// Validation(name: "greeting", pattern: /^(\w+) world!/)

Ranges:

let lyrics = """
  So it's gonna be forever
  Or it's gonna go down in flames
  """

let possibleEndings = Regex("it's gonna (.+)")
    .allMatches(in: lyrics)
    .flatMap { $0.captureRanges[0] }
    .map { lyrics[$0] }

// it's gonna: ["be forever", "go down in flames"]

Installation

Regex supports Swift 4.2 and above, on all Swift platforms.

Swift Package Manager

Add a dependency to your Package.swift:

let package = Package(
  name: "MyPackage",
  dependencies: [
    // other dependencies...
    .package(url: "https://github.com/sharplet/Regex.git", from: "2.1.0"),
  ]
)

Carthage

Put this in your Cartfile:

github "sharplet/Regex" ~> 2.1

CocoaPods

Put this in your Podfile:

pod "STRegex", "~> 2.1"

Contributing

See CONTRIBUTING.md.

Development Setup

Swift Package Manager

Build and run the tests:

swift test

# or just

rake test:package

If you're on a Mac, testing on Linux is supported via Docker for Mac. Once Docker is set up, start a Linux shell:

rake docker

And run the tests via Swift Package Manager.

Xcode

xcpretty is recommended, for prettifying test output:

gem install xcpretty

Then run the tests:

# one of
rake test:osx
rake test:ios
rake test:tvos

Formatting & Linting

Regex uses SwiftFormat to maintain consistent code formatting.

Regex uses SwiftLint to validate code style. SwiftLint is automatically run against pull requests using Hound CI.

When submitting a pull request, running these tools and addressing any issues is much appreciated!

brew bundle
swiftformat .
swiftlint

License

See LICENSE.txt.

Comments
  • Linux compatibility and testing

    Linux compatibility and testing

    This fixed a couple issues with the library on Linux. Unfortunately, on Linux this library is only compatible with Swift version 3.1 and up.

    I also enabled testing with the SwiftPM on Linux. The SwiftPM tests don't run on macOS for an unknown reason, but they don't really need to since there are other testing methods for macOS.

    opened by sclukey 7
  • Convert `Regex.init` to a failable intialiser

    Convert `Regex.init` to a failable intialiser

    As discussed in #32, a failable initialiser is a good balance between convenience and safety. Previously, however, you'd at least get the failure reason printed to the console upon crashing. So this PR exposes a new static property Regex.error that will return the underlying error if a failure occurred during initialisation.

    Fixes #32.

    opened by sharplet 5
  • Problem installing via cocoapods (fatal: No names found, cannot describe anything)

    Problem installing via cocoapods (fatal: No names found, cannot describe anything)

    Hey,

    When attempting to install via cocoapods, I'm encountering the following error:

    Updating local specs repositories
    Analyzing dependencies
    Pre-downloading: `Regex` from `https://github.com/sharplet/Regex.git`
    fatal: No names found, cannot describe anything.
    [!] Unable to satisfy the following requirements:
    
    - `Regex (from `https://github.com/sharplet/Regex.git`)` required by `Podfile`
    

    I'm kind of new to ios programming -any idea what could be going wrong?

    opened by DeepAnchor 5
  • Modernize to work with Swift 4.2

    Modernize to work with Swift 4.2

    :wave: @sharplet

    No worries if you don't want this monster of a PR, but I thought I'd offer it back all the same.

    This has been tested to work with SPM 4.2 and 5.0, as well as Xcode 10.1 and 10.2 beta.

    Sorry for removing Quick & Nimble, but they were getting in the way of SPM working.

    opened by tonyarnold 4
  • Swift PM Intergration

    Swift PM Intergration

    Cannot import Regex into my project. swift package update command tells me:
    error: the package has an unsupported layout, unexpected source file(s) found: /blablabla/Packages/Regex-0.3.1/Tests/OptionsSpec.swift, /blablabla/Packages/Regex-0.3.1/Tests/RegexSpec.swift, /blablabla/Packages/Regex-0.3.1/Tests/StringReplacementSpec.swift fix: move the file(s) inside a module

    opened by OdNairy 4
  • Added DotMatchesLineSeparators and updated Quick version

    Added DotMatchesLineSeparators and updated Quick version

    I have noticed myself quite a lot using this Regex framework for looking for paragraphs of text. One feature that I found was missing was dots match newlines. I decided to add that feature as an option for this framework.

    I also updated the Quick and Nimble versions to the latest version.

    opened by ninjaprawn 4
  • Regex.matches does not exist

    Regex.matches does not exist

    I was testing the Regex object and the README has an example using matches but it does not exist.

    Regex("Custom from:([0-9]+) to:([0-9]+)").matches(value) //error
    

    Another thing, is it normal the first capture to be the full value?

    let matchResult = Regex("Custom from:([0-9]+) to:([0-9]+)").match(value)
    // value e.g.: Custom from:1451811437 to:1452329837
    
    print(matchResult.captures.count) //prints 3
    print(matchResult.captures[0]) //prints Custom from:1451811437 to:1452329837
    print(matchResult.captures[1]) //prints 1451811437
    print(matchResult.captures[2]) //prints 1452329837
    
    opened by ricardopereira 4
  • Regex shouldn't be StringLitteralConvertible

    Regex shouldn't be StringLitteralConvertible

    As convenient as this may seem, Regex should not be a StringLiteralConvertible.

    Consider this code:

    func crasher(s: String) {
        switch s {
        case "*starred*":
             print("starred")
        case "any":
             print("any")
        default:
            print("unknown")
        }
    }
    

    Calling the crasher function crashes the app. Why? Because the case string is being silently converted to a Regex instance by the way of its StringLiteralConvertible initializer!

    In other words, simply using Regex in an application silently turns all case string tests into Regex instances.

    This has two drawbacks:

    • it hampers performance when not needed
    • it risks crashing the application, like in the example above, because the string is not a valid regex.

    Moreover, your example correctly shows a correct case statement using an explicit Regex instance.

    Simply removing conformance to the StringLiteralConvertible protocol will fix this issue.

    Thanks for a nice µframework!

    opened by fpillet 4
  • Linux support

    Linux support

    So, some day it looks like NSRegularExpression will be ported to Linux. \o/

    At the time of writing, the implementation is stubbed out and throws a runtime error: https://github.com/apple/swift-corelibs-foundation/blob/0254bc20d453626494d0e51d0cae35cc61ee3e46/Foundation/NSRegularExpression.swift.

    ~~Theoretically this should mean that you can compile and link against Regex on Linux, but when I tested it I got some linker errors. For now, I've filed a bug here: https://bugs.swift.org/browse/SR-82.~~

    opened by sharplet 4
  • NSRegularExpressionOptions?

    NSRegularExpressionOptions?

    I'm personally fairly happy with the defaults, but if there's enough demand for some options it would be good to look into.

    Case (in)sensitivity is one consideration.

    opened by sharplet 4
  • Add new MatchResult.captureRanges property

    Add new MatchResult.captureRanges property

    Just found an old branch where I'd been intending to make MatchResult.range public (now taken care of by #54).

    This change adds a complementary captureRanges property, and adds an internal Memo helper to avoid doing range conversions every time the property is accessed. It should be safe to keep accessing the array in constant time.

    opened by sharplet 3
  • Specify swift version

    Specify swift version

    Getting the following version during build. I can get around that by specifying the version in the consuming pod, but would be nice if the reason was fixed in the dependency itself:

        - `STRegex` does not specify a Swift version and none of the targets (`Runner`) integrating it have the `SWIFT_VERSION` attribute set. Please contact the author or set the `SWIFT_VERSION`
        attribute in at least one of the targets that integrate this pod.
    
    opened by vaind 0
  • Different replace behavior

    Different replace behavior

    Hi,

    I'm trying to remove the contents of a string matching the following regex: (\((?:[A-N]\d?(?:, )?)+\)).

    The idea is to remove these allergen-notices from a string like this:

    Frikadelle von Rind und Schwein (A, A1, C, I, J) mit Paprika-Zwiebelgemüse (J), dazu Spätzle (A, A1, C)

    I tried the following:

    let regex = Regex(#" (\((?:[A-N]\d?(?:, )?)+\))"#)
    let title = oldTitle.replacingAll(matching: regex, with: "")
    

    For some reason this leads to "Paprika-Zwiebelgemüse (J)" being turned into "Paprika-Zwiebelgemüs)" and not "Paprika-Zwiebelgemüse" as expected.

    When I use the native String API (.replacingOccurrences(of: #" (\((?:[A-N]\d?(?:, )?)+\))"#, with: "", options: .regularExpression)), it works like it should.

    Is this a bug in Regex or am I doing something wrong? This is on iOS in case that's relevant.

    Thanks!

    opened by kiliankoe 0
  • Crash when matching LF against CRLF

    Crash when matching LF against CRLF

    The following code crashes, because the matched string breaks extended grapheme cluster. The range of swift string is invalid.

    let source = "\r\n"
    let regex = Regex("\n")
    let match = regex.firstMatch(in: source)!
    let matchedString = match.matchedString // crash here
    XCTAssertEqual(matchedString, "\n")
    
    opened by ddddxxx 0
  • We should be using Substring

    We should be using Substring

    While working on https://github.com/sharplet/Regex/pull/69, I realised that we’re doing far more string copying than we should be. The built in Substring type is a perfect way to represent substrings as “real” strings in a performant way. MatchResult is a bundle of ranges that map onto a single string, and should really be exposing Substring in its API as much as possible to avoid the many unnecessary copies.

    It would have been nice if I’d noticed this before 2.0, but unfortunately that ship has sailed. If we get another opportunity to make breaking changes, this is a perfect one.

    opened by sharplet 0
  • NSAttributedString support?

    NSAttributedString support?

    Accessing the underlying matched NSRange for use with NSAttributedString has come up in both #26 and #37.

    At this point I still consider the Foundation types implementation details. There are gotchas related the use of UTF-16, and I'd prefer to err on the side of safety where it's not possible to make that kind of mistake.

    There are probably two main considerations stopping me from adding NSAttributedString support at the moment:

    • So far I've endeavoured to only expose types in the standard library in the public API. NSAttributedString isn't bridged, so I've avoided supporting it. If there was a first-class attributed string value type in the standard library, I think I'd be willing to support it.
    • ~At this point I'm still interested in reserving the right to replace the regular expression engine with something else, like PCRE.~

    ~In a world where Foundation is fully supported and cross-platform (and NSRegularExpression is implemented—it wasn't last time I checked), these reasons will start to hold less water.~

    Update: Moving away from NSRegularExpression at this stage is unlikely. So the main issue here seems like an API design one.

    enhancement 
    opened by sharplet 1
Releases(2.1.1)
  • 2.1.1(Mar 2, 2020)

  • 2.1.0(Apr 21, 2019)

    New:

    • Adds a new option regex option .allowCommentsAndWhitespace, allowing for richer, self-documenting regular expression patterns. (#66 — thanks @remithaunay!)

    Improved:

    • Updated internals to use the modern built in conversions between NSRange and Range<String.Index>. This should improve performance and potentially correctness! (#69)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Mar 29, 2019)

    Say hello to Regex version 2, including support for Swift 5! This release adds no new functionality, but drops support for Swift versions less than 4.2. Regex 2 should otherwise be fully compatible with Regex 1.1.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Aug 4, 2017)

    Regex now speaks Swift 4! 🎉

    Added:

    • The Regex type now conforms to Codable, so you can encode and decode regular expressions to your heart's content. (#52)
    • MatchResult has a new range property. (#54, thanks @mezhevikin!)
    • To go with MatchResult.range, there's also the captureRanges property, allowing you to work with the ranges of capture groups. (#59)

    Fixed:

    • Regex now handles the newly overhauled String index API, maintaining that sweet, sweet Unicode correctness, whatever your chosen Swift version. (#57, 7952baebc8cf08597c2810496b7e777e6212be00, 1a90514f101436f8f92f06e4c5796e8e58458285, thanks @wspl!)

    Thanks for using Regex!

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Jun 13, 2017)

    Regex is now officially at 1.0.0! 🎉

    Here's a quick hit list of features:

    • Easily and safely create regular expressions
    • When creating a regular expression from a static string, no error handling required
    • Great pattern-matching support via Regex.lastMatch
    • Type safe access to capture groups
    • Convenient extensions to String to support find and replace

    I hope you enjoy using Regex!

    Source code(tar.gz)
    Source code(zip)
  • 0.4.3(Dec 12, 2016)

  • 0.4.2(Sep 25, 2016)

    This should add full Swift 3 support for swiftpm and CocoaPods users. Carthage users should be able to opt into Swift 3 using the --toolchain option to carthage build.

    Breaking changes to drop Swift 2 support and adopt the Swift API Design Guidelines will be made in a future release.

    Source code(tar.gz)
    Source code(zip)
  • 0.4.1(Sep 15, 2016)

  • 0.4.0(Aug 22, 2016)

    Added:

    • New initialiser Regex.init(string:) that throws if the pattern is invalid. Previously it wasn't possible to recover from this scenario.

    Changed:

    • The existing Regex.init(_:) initialiser now accepts a StaticString instead of a String (meaning that the string must exist statically at compile time), and will trap if an invalid pattern is provided. For dynamically created strings, use Regex.init(string:) instead.

    Removed:

    • Regex no longer conforms to StringLiteralConvertible. Use Regex.init(_:) instead.

    Regex now supports Xcode 8 and Swift 2.3!

    Source code(tar.gz)
    Source code(zip)
  • 0.3.1(Feb 1, 2016)

    Added

    • New String methods for performing find and replace operations (#31)
      • replaceFirstMatching(_:with:) - replaces the first match of the given regex with the replacement template
      • replaceAllMatching(_:with:) - replaces all matches of the given regex with the replacement template
      • Non-muting versions of each method for convenience
    • New Regex.lastMatch static property that gives access to the last match result when pattern matching (#27)
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Dec 23, 2015)

    Added

    • Support for watchOS 2.0+ (#6, #24)
    • Support for tvOS 9.0+ (#7. #24)
    • Fully documented public API (#23)

    Fixed

    • When accessing an optional capture group (e.g., "(foo)?"), an out of bounds error would cause a crash. (#22, #20)

    Changed

    • The type of MatchResult.captures has changed from [String] to [String?], in order to correctly handle optional capture groups. (#22, #20)
    • Regex.init now internally uses fatalError() with a meaningful message, instead of try!
    Source code(tar.gz)
    Source code(zip)
  • 0.2.5(Dec 8, 2015)

    • Added: A new Regex.Options type with various options for changing matching behaviour.
    • Fixed: The podspec didn't specify a module name, so it was incorrectly set to STRegex.
    Source code(tar.gz)
    Source code(zip)
  • 0.2.4(Dec 7, 2015)

  • 0.2.3(Dec 4, 2015)

  • v0.2.2(Nov 4, 2015)

    • Add support for CocoaPods
    • Add support for OS X

    There's an existing pod named Regex on CocoaPods Trunk, so for now, CocoaPods installation is like so:

    pod "Regex", git: "https://github.com/sharplet/Regex.git"
    
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Oct 29, 2015)

  • v0.2(Oct 29, 2015)

Owner
Adam Sharp
Adam Sharp
Perl-like regex =~ operator for Swift

SwiftRegex Perl-like regex =~ operator for Swift This package implements a =~ string infix operator for use in testing regular expressions and retriev

Gregory Todd Williams 112 Oct 15, 2022
Easily deal with Regex in Swift in a Pythonic way

PySwiftyRegex Easily deal with Regex in Swift in a Pythonic way. 简体中文 日本語 한국어 This is Easy import PySwiftyRegex if let m = re.search("[Tt]his is (.*?

Ce Zheng 232 Oct 12, 2022
Regex class for Swift. Wraps NSRegularExpression.

Regex.swift install Use CocoaPods. Add to your Podfile: pod 'Regex' And then run pod install from the shell: $ pod install usage Simple use cases: Str

Bryn Bellomy 67 Sep 14, 2022
This is a repo for my implementation of Gang of Four Book: Software Design Patterns. All written in Swift.

GoF-Swift-Design-Patterns This repo is intended to implement the known Software Design Patterns from the Gang of Four book using Swift Programming Lan

Noor El-Din Walid 3 Jul 11, 2022
XRepository: lightweight implementation of Repository pattern in Swift

XRepository is based on QBRepository by QuickBirds Studios. It is lightweight im

Sashko Potapov 2 Jan 10, 2022
Specification pattern implemented in swift (iOS/OSX)

SpecificationPattern The Specification design pattern implemented in swift for iOS/OSX. In computer programming, the specification pattern is a partic

Simon Strandgaard 46 Sep 21, 2022
Learn about how SoulverCore can give Swift "better than regex" data parsing features (for many common tasks)

String Parsing with Soulver Core A declarative & type-safe approach to parsing data from strings SoulverCore gives you human-friendly, type-safe & per

Soulver 140 Nov 23, 2022
A Cross-Platform String and Regular Expression Library written in Swift.

Guitar ?? A Cross-Platform String and Regular Expression Library written in Swift. About This library seeks to add common string manipulation function

Arthur Ariel Sabintsev 659 Dec 27, 2022
🎯 PredicateKit allows Swift developers to write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions.

?? PredicateKit PredicateKit is an alternative to NSPredicate allowing you to write expressive and type-safe predicates for CoreData using key-paths,

Faiçal Tchirou 352 Jan 3, 2023
Swift-when - Expression switch support in Swift

Swift When - supporting switch expressions in Swift! What is it? Basically, it a

Gordan Glavaš 7 Nov 24, 2022
Math expression parser built with Point•Free's swift-parsing package

swift-math-parser Basic math expression parser built with Point•Free's swift-parsing package. NOTE: currently, this uses a fork of that fixes a parsin

Brad Howes 36 Dec 14, 2022
Pure Swift 2.0 S-expression Parser

SwiftExP This is an S-expression parser written in pure Swift 2.0, where pure means without making any necessary usage of Foundation APIs at its core.

Marius Rackwitz 16 Jul 25, 2021
Type-safe networking abstraction layer that associates request type with response type.

APIKit APIKit is a type-safe networking abstraction layer that associates request type with response type. // SearchRepositoriesRequest conforms to Re

Yosuke Ishikawa 1.9k Dec 30, 2022
A phantom type is a custom type that has one or more unused type parameters.

PhantomTypes A phantom type is a custom type that has one or more unused type parameters. Phantom types allow you to enforce type-safety without sacri

null 3 Nov 4, 2022
Harness the power of AutoLayout NSLayoutConstraints with a simplified, chainable and expressive syntax. Supports iOS and OSX Auto Layout

Masonry Masonry is still actively maintained, we are committed to fixing bugs and merging good quality PRs from the wider community. However if you're

null 18k Jan 5, 2023
FileKit is a Swift framework that allows for simple and expressive file management.

FileKit is a Swift framework that allows for simple and expressive file management.

Nikolai Vazquez 2.2k Jan 7, 2023
A lightweight but powerful network library with simplified and expressive syntax based on AFNetworking.

XMNetworking English Document XMNetworking 是一个轻量的、简单易用但功能强大的网络库,基于 AFNetworking 3.0+ 封装。 其中,XM 前缀是我们团队 Xcode-Men 的缩写。 简介 如上图所示,XMNetworking 采用中心化的设计思想

KANGZUBIN 981 Dec 29, 2022
✏️Expressive styling on terminal string. (chalk for swift)

Chalk Expressive styling on terminal string. Highlights Expressive API 256/TrueColor support Nest styles Auto downgrading to terminal supported color

Luo Xiu 59 Jun 10, 2022
✏️Expressive styling on terminal string. (chalk for swift)

Chalk Expressive styling on terminal string. Highlights Expressive API 256/TrueColor support Nest styles Auto downgrading to terminal supported color

Luo Xiu 59 Jun 10, 2022
Kukai Crypto Swift is a native Swift library for creating regular or HD wallets for the Tezos blockchain

Kukai Crypto Swift Kukai Crypto Swift is a native Swift library for creating regular and HD key pairs for the Tezos blockchain. Supporting both TZ1 (E

Kukai Wallet 2 Aug 18, 2022