[
  {
    "path": ".github/workflow/claude.yml",
    "content": "name: Claude Code\n\non:\n  issue_comment:\n    types: [created]\n  pull_request_review_comment:\n    types: [created]\n  issues:\n    types: [opened, assigned]\n  pull_request_review:\n    types: [submitted]\n\njobs:\n  claude:\n    if: |\n      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||\n      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||\n      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||\n      (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n      issues: write\n      id-token: write\n      actions: read # Required for Claude to read CI results on PRs\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n\n      - name: Run Claude Code\n        id: claude\n        uses: anthropics/claude-code-action@beta\n        with:\n          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}\n\n          # This is an optional setting that allows Claude to read CI results on PRs\n          additional_permissions: |\n            actions: read\n\n          # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1)\n          # model: \"claude-opus-4-1-20250805\"\n          model: ${{ vars.ANTHROPIC_MODEL }}\n\n          # Optional: Customize the trigger phrase (default: @claude)\n          # trigger_phrase: \"/claude\"\n\n          # Optional: Trigger when specific user is assigned to an issue\n          # assignee_trigger: \"claude-bot\"\n\n          # Optional: Allow Claude to run specific commands\n          # allowed_tools: \"Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)\"\n\n          # Optional: Add custom instructions for Claude to customize its behavior for your project\n          # custom_instructions: |\n          #   Follow our coding standards\n          #   Ensure all new code has tests\n          #   Use TypeScript for new files\n\n          # Optional: Custom environment variables for Claude\n          claude_env: |\n            ANTHROPIC_BASE_URL: ${{ vars.ANTHROPIC_BASE_URL }}\n"
  },
  {
    "path": ".gitignore",
    "content": "\n# Created by https://www.gitignore.io/api/xcode,macos,fastlane\n# Edit at https://www.gitignore.io/?templates=xcode,macos,fastlane\n\n### fastlane ###\n# fastlane - A streamlined workflow tool for Cocoa deployment\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/#source-control\n\n# fastlane specific\nfastlane/report.xml\nfastlane/Appfile\nfastlane/metadata/**/review_information/\nfastlane/keys\n\n# deliver temporary files\nfastlane/Preview.html\n\n# snapshot generated screenshots\nfastlane/screenshots\n\n# scan temporary files\nfastlane/test_output\n\n### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### Xcode ###\n# Xcode\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## User settings\nxcuserdata/\n\n## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)\n*.xcscmblueprint\n*.xccheckout\n\n## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)\nbuild/\nDerivedData/\n*.moved-aside\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\n\n## Xcode Patch\n*.xcodeproj/*\n!*.xcodeproj/project.pbxproj\n!*.xcodeproj/xcshareddata/\n!*.xcworkspace/contents.xcworkspacedata\n/*.gcno\n\n### Xcode Patch ###\n**/xcshareddata/WorkspaceSettings.xcsettings\n\n# End of https://www.gitignore.io/api/xcode,macos,fastlane\n"
  },
  {
    "path": ".swift-version",
    "content": "5.9\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "disabled_rules:\n  - todo\n  - trailing_whitespace\n  - colon\n  - identifier_name\n  - comma\n  - vertical_whitespace\n  - type_name\n  - trailing_comma\n  - multiple_closures_with_trailing_closure\nexcluded:\n  - Carthage\n  - Pods\nline_length:\n  - 200\n  - 220\nfunction_body_length:\n  - 200\n  - 300\ntype_body_length:\n  - 300\n  - 500\nfile_length:\n  - 500\n  - 700\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Repository Guidelines\n\n## Project Structure & Module Organization\n`RegEx+/` hosts the SwiftUI app: `HomeView.swift` drives navigation, `Views/`, `Editor/`, and `Library/` contain feature areas, and `CheatSheet/` holds localized regex tips backed by `RegEx.xcdatamodeld`. Assets and previews live in `Assets.xcassets` and `Preview Content/`. Localizations reside in per-language `.lproj` folders alongside `Localizable.xcstrings`. Use the Xcode project at `RegEx+.xcodeproj`; the `Build/` directory is derived output and should stay untracked. `fastlane/` stores App Store metadata flows, and `mise.toml` defines repeatable automation tasks.\n\n## Build, Test, and Development Commands\n- `open RegEx+.xcodeproj` — launch the workspace in Xcode for iterative SwiftUI development.\n- `xcodebuild -scheme \"RegEx+\" -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 15' build` — verify the iOS target from the command line.\n- `xcodebuild test -scheme \"RegEx+\" -destination 'platform=macOS'` — run XCTest targets (create or enable them before CI).\n- `mise run sc2tc` — refresh Traditional Chinese cheat-sheet resources via OpenCC.\n- `mise run pull-metadata` / `mise run push-metadata` — sync App Store metadata with Fastlane.\n\n## Coding Style & Naming Conventions\nFollow idiomatic Swift 5.9: four-space indentation, `UpperCamelCase` for types and `lowerCamelCase` for functions, properties, and Core Data entities. Prefer SwiftUI modifiers over imperative UIKit. Strings must be localized by adding keys to `Localizable.xcstrings` and the matching `.lproj` plist. SwiftLint runs as an Xcode build phase; ensure `swiftlint` is installed (e.g., `brew install swiftlint`) before pushing.\n\n## Testing Guidelines\nAuthor tests with XCTest and snapshot SwiftUI previews where appropriate. Group specs by feature (e.g., `LibraryViewTests.swift`) and name methods `test_<scenario>_<expected>()`. Run `xcodebuild test` against both Catalyst and iOS destinations when the change affects shared logic. Aim to cover regex evaluation, Core Data persistence, and localization fallbacks; flag gaps in PRs if coverage is impractical.\n\n## Commit & Pull Request Guidelines\nGit history follows conventional prefixes (`feat:`, `fix:`, `chore:`). Keep subject lines under 72 characters and describe what changed and why. For pull requests, include a concise summary, affected platforms, and simulator or macOS screenshots when UI shifts. Link related issues, note localization or metadata follow-up steps, and confirm that SwiftLint and targeted builds/tests succeed locally. Avoid committing Fastlane API keys or other secrets under `fastlane/keys/`; use mocked or encrypted references instead.\n"
  },
  {
    "path": "CLAUDE.md",
    "content": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Build Commands\n\n- **Build project**: Use Xcode GUI or `xcodebuild -project RegEx+.xcodeproj -scheme RegEx+ build`\n- **Run SwiftLint**: Automatically runs during build via build phase, or manually with `swiftlint` (requires installation via Homebrew)\n- **Localization conversion**: `mise run sc2tc` (converts Simplified Chinese to Traditional Chinese using OpenCC)\n\n## Architecture Overview\n\nRegEx+ is a SwiftUI-based Regular Expression tool that supports both iOS and macOS via Mac Catalyst. The app uses Core Data with CloudKit for data persistence and synchronization.\n\n### Core Architecture Components\n\n- **SwiftUI App Structure**: Uses scene-based architecture with `AppDelegate.swift` and `SceneDelegate.swift`\n- **Navigation**: Master-detail navigation with `HomeView` as root, `LibraryView` as master, and `EditorView` as detail\n- **Data Layer**: Core Data + CloudKit integration via `NSPersistentCloudKitContainer` for automatic sync\n- **Custom Text Editing**: Specialized `RegExTextView` with syntax highlighting and live matching\n\n### Key Modules\n\n1. **CoreData+CloudKit**: Data persistence and cloud sync\n   - `DataManager.swift`: Singleton managing Core Data stack and CloudKit integration\n   - `RegEx.swift`: Core Data model for regex entries\n   - `RegExFetch.swift`: Fetch request definitions\n\n2. **Editor**: Main regex editing interface\n   - `EditorView.swift`: SwiftUI view for regex editing\n   - `EditorViewModel.swift`: Business logic and state management\n\n3. **Library**: Regex collection management\n   - `LibraryView.swift`: Master list of saved regexes\n   - `LibraryItemView.swift`: Individual regex list items\n   - `LibraryView+Data.swift`: Data manipulation extensions\n\n4. **Views/RegExTextView**: Custom text editing components\n   - `RegExTextView.swift`: UIKit-based text editor wrapper\n   - `RegExSyntaxHighlighter.swift`: Syntax highlighting engine\n   - `MatchesTextView.swift`: Display matching results\n   - `String+NSRange.swift`: String range utilities\n\n5. **CheatSheet**: Reference documentation\n   - Localized plist files for regex syntax reference\n\n### Platform Support\n\n- **Multi-platform**: iOS, iPadOS, and macOS (Mac Catalyst)\n- **Navigation adaptivity**: Automatically switches between single/double column navigation based on device\n- **Internationalization**: English, Simplified Chinese, Traditional Chinese\n- **CloudKit**: Automatic data sync across devices\n\n### Data Model\n\nThe app stores regex patterns with metadata in Core Data, automatically synced via CloudKit:\n- Name, pattern, test string, flags\n- Creation/modification dates\n- CloudKit integration for cross-device sync\n\n### Development Notes\n\n- Uses `#if targetEnvironment(macCatalyst)` for platform-specific code\n- SwiftLint integration via build phase\n- Traditional Chinese localization generated from Simplified Chinese via OpenCC\n- Custom UIKit text view integration within SwiftUI for advanced text editing features"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\nCopyright © 2020 Lex Tang, https://lex.sh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the “Software”), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# RegEx+\n\n[![Swift 5.9](https://img.shields.io/badge/swift-5.9-ED523F.svg?style=flat)](https://swift.org/download/)\n[![@lexrus](https://img.shields.io/badge/contact-@lexrus-336699.svg?style=flat)](https://twitter.com/lexrus)\n\n[<img src=\"https://cloud.githubusercontent.com/assets/219689/5575342/963e0ee8-9013-11e4-8091-7ece67d64729.png\" width=\"135\" height=\"40\" alt=\"AppStore\"/>](https://apps.apple.com/us/app/regex/id1511763524)\n\n> A Regular Expression tool built with **SwiftUI**. The App Store version is no longer open source as the project has transitioned to agentic coding workflows.\n\n![HeroImage](https://github.com/lexrus/RegExPlus/assets/219689/739896bf-c843-46b9-82f9-e1462562fe4b)\n\n## Features\n\n- [x] Universal SwiftUI app for macOS and iOS\n- [x] Regex editor with live match highlighting\n- [x] Substitution template preview with copy-to-clipboard support\n- [x] Share a regular expression from the editor\n- [x] Built-in regular expression cheat sheet\n- [x] CloudKit-backed sync via Core Data\n- [x] Localized into:\n  - [x] English\n  - [x] Simplified Chinese\n  - [x] Traditional Chinese\n  - [x] Spanish\n  - [x] German\n  - [x] Japanese\n  - [x] French\n  - [x] Italian\n  - [x] Korean\n  - [x] Dutch\n  - [x] Polish\n\n## License\n\nThis code is distributed under the terms and conditions of the MIT license.\n"
  },
  {
    "path": "RegEx+/About/AboutView.swift",
    "content": "//\n//  AboutView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/24.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\nimport StoreKit\nimport AppAboutView\n\nstruct AboutView: View {\n    var body: some View {\n        AppAboutView.fromMainBundle(\n          appIcon: Image(.appIconForAboutView),\n          feedbackEmail: \"lexrus@gmail.com\",\n          appStoreID: \"1511763524\",\n          privacyPolicy: URL(string: \"https://lex.sh/regexplus/privacypolicy\")!,\n          copyrightText: \"©2026 lex.sh\",\n          appsShowcaseURL: URL(string: \"https://lex.sh/apps/apps.json\")\n        )\n        .background(Color.init(white: 0.5, opacity: 0.1))\n        .navigationBarTitleDisplayMode(.inline)\n        .navigationBarTitle(\"RegEx+\")\n    }\n}\n\n#Preview {\n    AboutView()\n}\n"
  },
  {
    "path": "RegEx+/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/21.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport UIKit\nimport CoreData\nimport CloudKit\n\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    // MARK: UISceneSession Lifecycle\n\n    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {\n        // Called when a new scene session is being created.\n        // Use this method to select a configuration to create the new scene with.\n        return UISceneConfiguration(name: \"Default Configuration\", sessionRole: connectingSceneSession.role)\n    }\n\n    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {\n        // Called when the user discards a scene session.\n        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n    }\n\n    override func buildMenu(with builder: UIMenuBuilder) {\n        super.buildMenu(with: builder)\n\n        // Ensure that the builder is modifying the menu bar system.\n        guard builder.system == UIMenuSystem.main else { return }\n\n        builder.remove(menu: .help)\n    }\n\n}\n"
  },
  {
    "path": "RegEx+/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"1.000\",\n          \"green\" : \"0.400\",\n          \"red\" : \"0.000\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0.900\",\n          \"green\" : \"0.300\",\n          \"red\" : \"0.000\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "RegEx+/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"icon_40pt.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"filename\" : \"icon_20pt@3x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"filename\" : \"icon_29pt@2x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"filename\" : \"icon_29pt@3x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"filename\" : \"icon_40pt@2x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"filename\" : \"icon_60pt@2x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"filename\" : \"icon_60pt@2x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"filename\" : \"icon_60pt@3x.png\",\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"filename\" : \"icon_20pt.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"filename\" : \"icon_40pt.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"filename\" : \"icon_29pt.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"filename\" : \"icon_29pt@2x.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"filename\" : \"icon_40pt.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"filename\" : \"icon_40pt@2x.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"filename\" : \"icon_76pt.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"76x76\"\n    },\n    {\n      \"filename\" : \"icon_76pt@2x.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"76x76\"\n    },\n    {\n      \"filename\" : \"icon_83.5@2x.png\",\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"83.5x83.5\"\n    },\n    {\n      \"filename\" : \"Icon.png\",\n      \"idiom\" : \"ios-marketing\",\n      \"scale\" : \"1x\",\n      \"size\" : \"1024x1024\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"mac128.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"mac256.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"mac256.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"mac512.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"mac512.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"512x512\"\n    },\n    {\n      \"filename\" : \"mac.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"512x512\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "RegEx+/Assets.xcassets/AppIconForAboutView.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"AppIconForAboutView.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "RegEx+/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "RegEx+/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina6_1\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"414\" height=\"896\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"RegEx+\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uh6-UG-ggI\">\n                                <rect key=\"frame\" x=\"150.5\" y=\"427.5\" width=\"113.5\" height=\"41\"/>\n                                <fontDescription key=\"fontDescription\" style=\"UICTFontTextStyleTitle0\"/>\n                                <nil key=\"textColor\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"^(\\w+)$\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontForContentSizeCategory=\"YES\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mtl-3p-SGW\">\n                                <rect key=\"frame\" x=\"20\" y=\"398\" width=\"374\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" style=\"UICTFontTextStyleHeadline\"/>\n                                <color key=\"textColor\" systemColor=\"secondaryLabelColor\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"mtl-3p-SGW\" secondAttribute=\"trailing\" constant=\"20\" id=\"8mK-0Y-Vwb\"/>\n                            <constraint firstItem=\"uh6-UG-ggI\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"IUg-rq-0FK\"/>\n                            <constraint firstItem=\"mtl-3p-SGW\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" constant=\"20\" id=\"Qas-mh-Sgd\"/>\n                            <constraint firstItem=\"uh6-UG-ggI\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"W5e-Db-s6l\"/>\n                            <constraint firstItem=\"uh6-UG-ggI\" firstAttribute=\"top\" secondItem=\"mtl-3p-SGW\" secondAttribute=\"bottom\" constant=\"8.5\" id=\"xQz-5B-3gd\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"52.173913043478265\" y=\"375\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <systemColor name=\"secondaryLabelColor\">\n            <color red=\"0.23529411759999999\" green=\"0.23529411759999999\" blue=\"0.26274509800000001\" alpha=\"0.59999999999999998\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </systemColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "RegEx+/CheatSheet/CheatSheetView.swift",
    "content": "//\n//  CheatSheetView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/21.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\n\n\n// Official documentation of NSRegularExpression\nprivate let kNSRegularExpressionDocumentLink = \"https://developer.apple.com/documentation/foundation/nsregularexpression\"\n\n\nstruct CheatSheetView: View {\n    @State var showingSafari = false\n    \n    @State var metacharacters: [CheatSheetPlist.Item] = []\n    @State var operators: [CheatSheetPlist.Item] = []\n    \n    var body: some View {\n        List {\n            Section(header: Text(\"Metacharacters\")) {\n                ForEach(metacharacters, id: \\.exp) {\n                    RowView(title: $0.exp, content: $0.des)\n                }\n            }\n            \n            Section(header: Text(\"Operators\")) {\n                ForEach(operators, id: \\.exp) {\n                    RowView(title: $0.exp, content: $0.des)\n                }\n            }\n        }\n        .navigationBarTitle(\"Cheat Sheet\")\n        .toolbar {\n            ToolbarItem(placement: .navigationBarTrailing) {\n                safariButton\n            }\n        }\n        .onAppear(perform: loadPlist)\n    }\n    \n    private func loadPlist() {\n        guard let url = Bundle.main.url(forResource: \"CheatSheet\", withExtension: \"plist\") else {\n            assertionFailure(\"Missing CheatSheet.plist!\")\n            return\n        }\n        \n        let plistDecoder = PropertyListDecoder()\n        \n        do {\n            let data = try Data(contentsOf: url)\n            let dict = try plistDecoder.decode(CheatSheetPlist.self, from: data)\n            metacharacters = dict.metacharacters\n            operators = dict.operators\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    private var safariButton: some View {\n        let url = URL(string: kNSRegularExpressionDocumentLink)!\n\n        return Button(action: {\n            #if targetEnvironment(macCatalyst)\n            UIApplication.shared.open(url)\n            #else\n            showingSafari.toggle()\n            #endif\n        }) {\n            Image(systemName: \"safari\")\n                .imageScale(.large)\n                .padding(EdgeInsets(top: 8, leading: 24, bottom: 8, trailing: 0))\n        }\n        .sheet(isPresented: $showingSafari, content: {\n            SafariView(url: url)\n        })\n    }\n}\n\nstruct CheatSheetView_Previews: PreviewProvider {\n    static var previews: some View {\n        NavigationView {\n            CheatSheetView()\n                .navigationBarTitle(\"Cheat Sheet\")\n        }\n    }\n}\n\nprivate struct RowView: View {\n    var title: String\n    var content: String\n    \n    var body: some View {\n        VStack(alignment: .leading, spacing: 3) {\n            Text(title)\n                .font(.headline)\n                .foregroundColor(.accentColor)\n            Text(content)\n                .font(.subheadline)\n        }\n        .padding(.vertical, 6)\n    }\n}\n\nstruct CheatSheetPlist: Decodable {\n    struct Item: Decodable, Hashable {\n        var exp: String\n        var des: String\n    }\n    \n    var metacharacters: [Item]\n    var operators: [Item]\n    \n}\n"
  },
  {
    "path": "RegEx+/CoreData+CloudKit/DataManager.swift",
    "content": "//\n//  DataManager.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/3.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport CoreData\nimport CloudKit\n\n\nclass DataManager {\n    \n    static let shared = DataManager()\n    \n    lazy var persistentContainer: NSPersistentCloudKitContainer = {\n        \n        let container = NSPersistentCloudKitContainer(name: \"RegEx\")\n        \n        guard let description = container.persistentStoreDescriptions.first else {\n            fatalError(\"No Descriptions found\")\n        }\n        description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)\n        \n        container.viewContext.automaticallyMergesChangesFromParent = true\n        container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump\n        \n        container.loadPersistentStores(completionHandler: { (_, error) in\n            if let error = error as NSError? {\n                fatalError(\"Unresolved error \\(error), \\(error.userInfo)\")\n            }\n        })\n        \n//        NotificationCenter.default.addObserver(self, selector: #selector(self.processUpdate), name: .NSPersistentStoreRemoteChange, object: nil)\n        \n        return container\n    }()\n    \n    // MARK: - Initialize CloudKit schema\n    \n    func initializeCloudKitSchema() {\n        do {\n            try persistentContainer.initializeCloudKitSchema(options: NSPersistentCloudKitContainerSchemaInitializationOptions.printSchema)\n        } catch {\n            print(error.localizedDescription)\n        }\n    }\n    \n    // MARK: - Core Data Saving support\n\n    func saveContext() {\n        let context = persistentContainer.viewContext\n        guard context.hasChanges else {\n            return\n        }\n        do {\n            try context.save()\n        } catch {\n            // Replace this implementation with code to handle the error appropriately.\n            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.\n            let nserror = error as NSError\n            fatalError(\"Unresolved error \\(nserror), \\(nserror.userInfo)\")\n        }\n    }\n    \n    @objc\n    func processUpdate(notification: NSNotification) {\n        operationQueue.addOperation {\n            let context = self.persistentContainer.newBackgroundContext()\n            context.performAndWait {\n                let items: [RegEx]\n                do {\n                    try items = context.fetch(RegEx.fetchAllRegEx())\n                } catch {\n                    let nserror = error as NSError\n                    fatalError(\"Unresolved error \\(nserror), \\(nserror.userInfo)\")\n                }\n\n                items.forEach {\n                    print(\"NAME: \\($0.name) !!!!\")\n                }\n                \n                if context.hasChanges {\n                    do {\n                        try context.save()\n                    } catch {\n                        let nserror = error as NSError\n                        fatalError(\"Unresolved error \\(nserror), \\(nserror.userInfo)\")\n                    }\n                }\n            }\n            \n        }\n    }\n    \n    private lazy var operationQueue: OperationQueue = {\n       var queue = OperationQueue()\n        queue.maxConcurrentOperationCount = 1\n        return queue\n    }()\n    \n}\n"
  },
  {
    "path": "RegEx+/CoreData+CloudKit/RegEx.swift",
    "content": "//\n//  RegEx+CoreDataClass.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/3.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n//\n\nimport Foundation\nimport CoreData\n\n@objc(RegEx)\npublic class RegEx: NSManagedObject {\n\n    @NSManaged public var name: String\n    @NSManaged public var raw: String\n    @NSManaged public var sample: String\n    @NSManaged public var substitution: String\n    @NSManaged public var createdAt: Date\n    @NSManaged public var updatedAt: Date\n    \n    @NSManaged public var allowCommentsAndWhitespace: Bool\n    @NSManaged public var anchorsMatchLines: Bool\n    @NSManaged public var caseInsensitive: Bool\n    @NSManaged public var dotMatchesLineSeparators: Bool\n    @NSManaged public var ignoreMetacharacters: Bool\n    @NSManaged public var useUnicodeWordBoundaries: Bool\n    @NSManaged public var useUnixLineSeparators: Bool\n\n    convenience init(name: String = \"Untitled\") {\n        self.init()\n        self.name = name\n        self.raw = \"\"\n        self.sample = \"\"\n        self.substitution = \"\"\n        self.createdAt = Date()\n        self.updatedAt = Date()\n    }\n    \n    public var regularExpressionOptions: NSRegularExpression.Options {\n        var options: NSRegularExpression.Options = []\n        if allowCommentsAndWhitespace {\n            options.insert(.allowCommentsAndWhitespace)\n        }\n        if anchorsMatchLines {\n            options.insert(.anchorsMatchLines)\n        }\n        if caseInsensitive {\n            options.insert(.caseInsensitive)\n        }\n        if dotMatchesLineSeparators {\n            options.insert(.dotMatchesLineSeparators)\n        }\n        if ignoreMetacharacters {\n            options.insert(.ignoreMetacharacters)\n        }\n        if useUnicodeWordBoundaries {\n            options.insert(.useUnicodeWordBoundaries)\n        }\n        if useUnixLineSeparators {\n            options.insert(.useUnixLineSeparators)\n        }\n        return options\n    }\n    \n    public var flagOptions: String {\n        \"\"\n            + (caseInsensitive ? \"i\" : \"\")\n            + (allowCommentsAndWhitespace ? \"x\" : \"\")\n            + (dotMatchesLineSeparators ? \".\" : \"\")\n            + (anchorsMatchLines ? \"m\" : \"\")\n            + (useUnicodeWordBoundaries ? \"w\" : \"\")\n    }\n    \n    public override var description: String {\n        \"/\\(raw)/\\(flagOptions)\"\n    }\n\n    public func isEqual(to object: RegEx) -> Bool {\n        name == object.name\n        && regularExpressionOptions == object.regularExpressionOptions\n        && raw == object.raw\n        && sample == object.sample\n        && substitution == object.substitution\n        && allowCommentsAndWhitespace == object.allowCommentsAndWhitespace\n        && anchorsMatchLines == object.anchorsMatchLines\n        && caseInsensitive == object.caseInsensitive\n        && dotMatchesLineSeparators == object.dotMatchesLineSeparators\n        && ignoreMetacharacters == object.ignoreMetacharacters\n        && useUnicodeWordBoundaries == object.useUnicodeWordBoundaries\n        && useUnixLineSeparators == object.useUnixLineSeparators\n    }\n\n}\n"
  },
  {
    "path": "RegEx+/CoreData+CloudKit/RegExFetch.swift",
    "content": "//\n//  RegExFetch.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/3.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport CoreData\n\n\nextension RegEx {\n    \n    @nonobjc public class func fetchRequest() -> NSFetchRequest<RegEx> {\n        NSFetchRequest<RegEx>(entityName: \"RegEx\")\n    }\n\n    @nonobjc public class func fetchAllRegEx() -> NSFetchRequest<RegEx> {\n        let req: NSFetchRequest<RegEx> = RegEx.fetchRequest()\n        req.sortDescriptors = [\n            NSSortDescriptor(key: \"createdAt\", ascending: false),\n            NSSortDescriptor(key: \"updatedAt\", ascending: false)\n        ]\n        return req\n    }\n\n    @nonobjc public class func fetch(byID ID: NSManagedObjectID) -> NSFetchRequest<RegEx> {\n        let req: NSFetchRequest<RegEx> = RegEx.fetchRequest()\n        req.predicate = NSPredicate(format: \"self.objectID IN %@\", ID)\n        return req\n    }\n\n}\n"
  },
  {
    "path": "RegEx+/Editor/EditorView.swift",
    "content": "//\n//  EditorView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/21.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct EditorView: View, Equatable {\n\n    static func == (lhs: EditorView, rhs: EditorView) -> Bool {\n        lhs.regEx.objectID == rhs.regEx.objectID\n    }\n\n    let regEx: RegEx\n    @StateObject private var viewModel = EditorViewModel()\n    @State private var isSharePresented = false\n    @State private var copyButtonText = \"Copy\"\n    @State private var isFlowViewVisible = false\n\n    init(regEx: RegEx) {\n        self.regEx = regEx\n    }\n\n    var body: some View {\n        Group {\n            if let regExBinding = Binding($viewModel.regEx) {\n                List {\n                    Section(header: Text(\"Name\")) {\n                        TextField(\"Name\", text: regExBinding.name)\n                            .font(.headline)\n                    }\n\n                    RegExTextViewSection(regEx: regExBinding)\n\n                    Section(header: FlowViewHeaderView(isVisible: $isFlowViewVisible)) {\n                        if isFlowViewVisible {\n                            RegExFlowView(pattern: regExBinding.wrappedValue.raw)\n                                .frame(minHeight: 80)\n                        }\n                    }\n\n                    Section(header: SampleHeaderView(count: viewModel.matches.count)) {\n                        MatchesTextView(\n                            \"$56.78 $90.12\",\n                            text: regExBinding.sample,\n                            matches: $viewModel.matches\n                        )\n                        .equatable()\n                        .padding(kTextFieldPadding)\n                    }\n\n                    SubstitutionSection(\n                        regExBinding: regExBinding,\n                        substitutionResult: viewModel.substitutionResult,\n                        copyButtonText: copyButtonText,\n                        copyAction: copyToClipboard\n                    )\n                }\n                .navigationTitle(regExBinding.name)\n                .toolbar {\n#if !targetEnvironment(macCatalyst)\n                    ToolbarItemGroup(placement: .navigationBarTrailing) {\n                        shareButton.padding()\n                        cheatSheetButton().padding(EdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 0))\n                    }\n#endif\n                }\n                .gesture(dismissKeyboardDesture)\n                .listStyle(InsetGroupedListStyle())\n                .onDisappear(perform: {\n                    viewModel.updateLastModified()\n                    DataManager.shared.saveContext()\n                })\n            } else {\n                Text(\"Loading...\")\n                    .navigationTitle(\"RegEx+\")\n            }\n        }\n        .onAppear {\n            viewModel.configure(with: regEx)\n        }\n    }\n\n    private func copyToClipboard() {\n        UIPasteboard.general.string = viewModel.substitutionResult\n        copyButtonText = \"Copied\"\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            copyButtonText = \"Copy\"\n        }\n    }\n\n    // https://stackoverflow.com/questions/56491386/how-to-hide-keyboard-when-using-swiftui\n    private var dismissKeyboardDesture: some Gesture {\n        DragGesture().onChanged { _ in\n            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)\n        }\n    }\n\n    private var shareButton: some View {\n        Button(action: {\n            self.isSharePresented = true\n        }) {\n            Image(systemName: \"square.and.arrow.up\")\n                .imageScale(.large)\n        }\n        .accessibilityLabel(\"Share\")\n        .accessibilityHint(\"Share this regular expression\")\n        .sheet(isPresented: $isSharePresented) {\n            if let regEx = viewModel.regEx {\n                ActivityViewController(activityItems: [regEx.description])\n            }\n        }\n    }\n}\n\nprivate func cheatSheetButton() -> some View {\n#if targetEnvironment(macCatalyst)\n    ZStack {\n        Image(systemName: \"wand.and.stars\")\n            .imageScale(.large)\n            .foregroundColor(.accentColor)\n        NavigationLink(destination: CheatSheetView()) {\n            EmptyView()\n        }\n        .opacity(0)\n    }\n    .accessibilityLabel(\"Cheat Sheet\")\n    .accessibilityHint(\"View regular expression reference guide\")\n#else\n    NavigationLink(destination: CheatSheetView()) {\n        Image(systemName: \"wand.and.stars\")\n            .imageScale(.large)\n            .foregroundColor(.accentColor)\n    }\n    .accessibilityLabel(\"Cheat Sheet\")\n    .accessibilityHint(\"View regular expression reference guide\")\n#endif\n}\n\nprivate struct RegExTextViewSection: View {\n\n    @Binding var regEx: RegEx\n    @State private var isOptionsVisible = false\n\n    var body: some View {\n        Section(header: Text(\"Regular Expression\")) {\n#if targetEnvironment(macCatalyst)\n\n            HStack {\n                RegExTextView(\n                    \"Type RegEx here\",\n                    text: $regEx.raw,\n                    showShortcutBar: false,\n                    highlightingMode: .regularExpression(regEx.regularExpressionOptions)\n                )\n                    .equatable()\n                    .padding(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 5))\n\n                cheatSheetButton()\n                    .frame(width: 20)\n            }\n\n#else\n\n            RegExTextView(\n                \"Type RegEx here\",\n                text: $regEx.raw,\n                showShortcutBar: true,\n                highlightingMode: .regularExpression(regEx.regularExpressionOptions)\n            )\n                .padding(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 5))\n\n#endif\n\n            Button(action: {\n                isOptionsVisible.toggle()\n            }) {\n                HStack {\n                    Text(\"Options\")\n\n                    if !isOptionsVisible {\n                        Spacer()\n                        VStack(alignment: .trailing) {\n                            if regEx.caseInsensitive {\n                                Text(\"Case Insensitive\")\n                            }\n                            if regEx.allowCommentsAndWhitespace {\n                                Text(\"Allow Comments and Whitespace\")\n                            }\n                            if regEx.ignoreMetacharacters {\n                                Text(\"Ignore Metacharacters\")\n                            }\n                            if regEx.anchorsMatchLines {\n                                Text(\"Anchors Match Lines\")\n                            }\n                            if regEx.dotMatchesLineSeparators {\n                                Text(\"Dot Matches Line Separators\")\n                            }\n                            if regEx.useUnixLineSeparators {\n                                Text(\"Use Unix Line Separators\")\n                            }\n                            if regEx.useUnicodeWordBoundaries {\n                                Text(\"Use Unicode Word Boundaries\")\n                            }\n                        }\n                        .font(.footnote)\n                    }\n                }\n                .foregroundColor(isOptionsVisible ? .secondary : .accentColor)\n            }\n\n            if isOptionsVisible {\n                Toggle(\"Case Insensitive\", isOn: $regEx.caseInsensitive)\n                Toggle(\"Allow Comments and Whitespace\", isOn: $regEx.allowCommentsAndWhitespace)\n                Toggle(\"Ignore Metacharacters\", isOn: $regEx.ignoreMetacharacters)\n                Toggle(\"Anchors Match Lines\", isOn: $regEx.anchorsMatchLines)\n                Toggle(\"Dot Matches Line Separators\", isOn: $regEx.dotMatchesLineSeparators)\n                Toggle(\"Use Unix Line Separators\", isOn: $regEx.useUnixLineSeparators)\n                Toggle(\"Use Unicode Word Boundaries\", isOn: $regEx.useUnicodeWordBoundaries)\n            }\n        }\n    }\n}\n\nprivate struct SampleFooterView: View {\n    var count: Int\n\n    private var matchesString: String {\n        return self.count == 1 ? \"1 match\" : \"\\(count) matches\"\n    }\n\n    var body: some View {\n        Text(matchesString)\n    }\n}\n\nprivate struct SampleHeaderView: View {\n    var count: Int\n\n    var body: some View {\n        HStack {\n            Text(\"Sample Text\")\n            if count > 0 {\n                Spacer()\n                Text(count == 1 ? \"1 match\" : \"\\(count) matches\")\n                    .font(.footnote)\n                    .foregroundColor(Color.secondary)\n                    .padding(EdgeInsets(top: 1, leading: 6, bottom: 1, trailing: 6))\n                    .overlay(\n                        RoundedRectangle(cornerRadius: 20)\n                            .stroke(Color.secondary, lineWidth: 1)\n                    )\n            }\n        }\n        .frame(minHeight: 20)\n    }\n}\n\nprivate let kTextFieldPadding = EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 5)\n\n#if DEBUG\nstruct EditorView_Previews: PreviewProvider {\n    private static var regEx: RegEx = {\n        var r: RegEx = RegEx(context: DataManager.shared.persistentContainer.viewContext)\n        r.name = \"Dollars\"\n        r.raw = #\"\\$?((\\d+)\\.?(\\d\\d)?)\"#\n        r.sample = \"$100.00 12.50 $10\"\n        r.substitution = \"$3\"\n        return r\n    }()\n\n    static var previews: some View {\n        Group {\n            NavigationView {\n                EditorView(regEx: regEx)\n            }\n            .environment(\\.sizeCategory, .extraLarge)\n            .previewLayout(.device)\n            .previewDevice(\"iPhone 11\")\n            NavigationView {\n                EditorView(regEx: regEx)\n            }\n            .previewDevice(\"iPhone 11\")\n            .preferredColorScheme(.dark)\n            .environment(\\.sizeCategory, .large)\n        }\n    }\n}\n#endif\n\nprivate struct SubstitutionSection: View {\n    @Binding var regExBinding: RegEx\n    let substitutionResult: String\n    let copyButtonText: String\n    let copyAction: () -> Void\n    \n    var body: some View {\n        Section(header: Text(\"Substitution Template\")) {\n#if targetEnvironment(macCatalyst)\n            TextField(\"Price: $$$1\\\\.$2\\\\n\", text: $regExBinding.substitution)\n                .padding(kTextFieldPadding)\n#else\n            RegExTextView(\n                \"Price: $$$1\\\\.$2\\\\n\",\n                text: $regExBinding.substitution,\n                showShortcutBar: true,\n                highlightingMode: .plainText\n            )\n                .padding(kTextFieldPadding)\n#endif\n        }\n\n        if !regExBinding.substitution.isEmpty {\n            Section(header: Text(\"Substitution Result\")) {\n                HStack {\n                    Text(substitutionResult)\n                        .padding(kTextFieldPadding)\n                    if !substitutionResult.isEmpty {\n                        Spacer()\n                        Button(action: copyAction) {\n                            Text(\"\\(copyButtonText)\")\n                                .font(.footnote)\n                                .foregroundColor(Color.accentColor)\n                                .padding(EdgeInsets(top: 1, leading: 6, bottom: 1, trailing: 6))\n                                .overlay(\n                                    RoundedRectangle(cornerRadius: 20)\n                                        .stroke(Color.accentColor, lineWidth: 1)\n                                )\n                        }\n                        .accessibilityLabel(\"Copy substitution result\")\n                        .accessibilityHint(\"Copies the substitution result to clipboard\")\n                    }\n                }\n            }\n        }\n    }\n}\n\nprivate struct FlowViewHeaderView: View {\n    @Binding var isVisible: Bool\n    \n    var body: some View {\n        Button(action: {\n            withAnimation {\n                isVisible.toggle()\n            }\n        }) {\n            HStack {\n                Text(\"Flow Diagram\")\n                Spacer()\n                Image(systemName: isVisible ? \"chevron.down\" : \"chevron.right\")\n                    .font(.caption)\n                    .foregroundColor(.secondary)\n            }\n        }\n        .foregroundColor(isVisible ? .primary : .accentColor)\n    }\n}\n"
  },
  {
    "path": "RegEx+/Editor/EditorViewModel.swift",
    "content": "//\n//  RegExEditorViewModel.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/25.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport Foundation\nimport Combine\n\n\nclass EditorViewModel : ObservableObject, Equatable {\n\n    @Published var regEx: RegEx?\n    \n    @Published var matches = [NSTextCheckingResult]()\n    @Published var substitutionResult = \"\"\n    \n    private var cancellables = Set<AnyCancellable>()\n    \n    init() {\n        self.regEx = nil\n        setupBindings()\n    }\n    \n    func configure(with regEx: RegEx) {\n        self.regEx = regEx\n    }\n    \n    private func setupBindings() {\n        let optionsObservable = $regEx\n            .compactMap { $0 }\n            .map(\\.regularExpressionOptions)\n        \n        let regExObservable = $regEx\n            .compactMap { $0 }\n            .map(\\.raw)\n            .throttle(for: 0.2, scheduler: RunLoop.main, latest: true)\n            .removeDuplicates()\n            .combineLatest(optionsObservable)\n            .compactMap { (raw, options) in\n                try? NSRegularExpression(pattern: raw, options: options)\n            }\n        \n        let sampleObservable = $regEx\n            .compactMap { $0 }\n            .map(\\.sample)\n            .throttle(for: 0.2, scheduler: RunLoop.main, latest: true)\n            .removeDuplicates()\n\n        let substitutionObservalbe = $regEx\n            .compactMap { $0 }\n            .map(\\.substitution)\n            .throttle(for: 0.2, scheduler: RunLoop.main, latest: true)\n            .removeDuplicates()\n\n        let subAndSampleObservable = substitutionObservalbe.combineLatest(sampleObservable)\n            .map { ($0.0, $0.1) }\n\n        regExObservable\n            .combineLatest(sampleObservable)\n            .sink { [weak self] (reg: NSRegularExpression, sample: String) in\n                let range = NSRange(location: 0, length: sample.count)\n                self?.matches = reg.matches(in: sample, options: [], range: range)\n            }\n            .store(in: &cancellables)\n        \n        regExObservable\n            .combineLatest(subAndSampleObservable)\n            .map { ($0, $1.0, $1.1) }\n            .sink { [weak self] (reg: NSRegularExpression, sub: String, sample: String) in\n                let range = NSRange(location: 0, length: sample.count)\n                self?.substitutionResult = reg.stringByReplacingMatches(\n                    in: sample,\n                    options: [],\n                    range: range,\n                    withTemplate: sub\n                )\n            }\n            .store(in: &cancellables)\n    }\n    \n    // Keep the old initializer for compatibility\n    convenience init(regEx: RegEx) {\n        self.init()\n        self.regEx = regEx\n    }\n    \n    func updateLastModified() {\n        if let regEx, regEx.hasChanges {\n            regEx.updatedAt = Date()\n        }\n    }\n\n    static func == (lhs: EditorViewModel, rhs: EditorViewModel) -> Bool {\n        if let lr = lhs.regEx, let rr = rhs.regEx {\n            return lr.isEqual(to: rr) == true\n            && lhs.substitutionResult == rhs.substitutionResult\n            && lhs.matches == rhs.matches\n        }\n        return false\n    }\n\n}\n"
  },
  {
    "path": "RegEx+/Editor/RegExFlowView.swift",
    "content": "//\n//  RegExFlowView.swift\n//  RegEx+\n//\n//  Created by Lex on 2026/4/11.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n// swiftlint:disable file_length type_body_length cyclomatic_complexity\n\nimport SwiftUI\nimport _RegexParser\n\nstruct RegExFlowView: View {\n    let pattern: String\n\n    private var diagram: FlowComponent {\n        var builder = FlowDiagramBuilder(source: pattern)\n        return builder.build()\n    }\n\n    private var breakdown: FlowPatternBreakdown {\n        FlowPatternBreakdownBuilder(source: pattern).build()\n    }\n\n    var body: some View {\n        VStack(alignment: .leading, spacing: 12) {\n            if pattern.isEmpty {\n                Text(\"Enter a regular expression to see the flow diagram\")\n                    .foregroundStyle(.secondary)\n                    .font(.footnote)\n                    .padding()\n            } else {\n                ScrollView(.horizontal, showsIndicators: true) {\n                    HStack {\n                        Spacer(minLength: 0)\n                        FlowDiagramView(component: diagram)\n                            .padding(.vertical, 4)\n                        Spacer(minLength: 0)\n                    }\n                    .frame(maxWidth: .infinity)\n                }\n\n                if breakdown.hasItems {\n                    PatternBreakdownView(breakdown: breakdown)\n                        .padding(.top, 4)\n                }\n            }\n        }\n        .frame(maxWidth: .infinity, alignment: .leading)\n        .padding(.vertical, 4)\n    }\n}\n\nprivate struct FlowDiagramBuilder {\n    let source: String\n    private var captureGroupIndex = 0\n\n    init(source: String) {\n        self.source = source\n    }\n\n    mutating func build() -> FlowComponent {\n        let ast = parseWithRecovery(source, .traditional)\n        var components = [FlowComponent]()\n\n        if let globalOptions = ast.globalOptions {\n            components.append(contentsOf: globalOptions.options.map { option in\n                .node(\n                    FlowNode(\n                        style: .directive,\n                        label: sourceText(for: option.location) ?? \"Options\"\n                    )\n                )\n            })\n        }\n\n        let root = component(from: ast.root)\n        switch root {\n        case .sequence(let children):\n            components.append(contentsOf: children)\n        case .empty:\n            break\n        default:\n            components.append(root)\n        }\n\n        return normalizedSequence(components)\n    }\n\n    private mutating func component(from node: AST.Node) -> FlowComponent {\n        switch node {\n        case .alternation(let alternation):\n            var branches = [[FlowComponent]]()\n            for child in alternation.children {\n                branches.append(branch(from: child))\n            }\n            return .alternation(branches)\n\n        case .concatenation(let concatenation):\n            var children = [FlowComponent]()\n            for child in concatenation.children {\n                if let component = semanticComponent(from: child) {\n                    children.append(component)\n                }\n            }\n            return normalizedSequence(children)\n\n        case .group(let group):\n            let groupKind = group.kind.value\n            return .group(\n                FlowGroup(\n                    style: style(for: groupKind),\n                    title: title(for: groupKind, captureReference: nextCaptureReference(for: groupKind)),\n                    content: component(from: group.child)\n                )\n            )\n\n        case .conditional(let conditional):\n            return .group(\n                FlowGroup(\n                    style: .assertion,\n                    title: \"Conditional \\(conditionLabel(for: conditional.condition))\",\n                    content: .alternation([\n                        branch(from: conditional.trueBranch),\n                        branch(from: conditional.falseBranch)\n                    ])\n                )\n            )\n\n        case .quantification(let quantification):\n            return .quantified(\n                component(from: quantification.child),\n                quantifier(for: quantification)\n            )\n\n        case .quote(let quote):\n            return .node(\n                FlowNode(\n                    style: .literal,\n                    label: sourceText(for: quote.location) ?? quote.literal\n                )\n            )\n\n        case .trivia:\n            return .empty\n\n        case .interpolation(let interpolation):\n            return .node(\n                FlowNode(\n                    style: .directive,\n                    label: sourceText(for: interpolation.location) ?? interpolation.contents\n                )\n            )\n\n        case .atom(let atom):\n            return .node(flowNode(for: atom))\n\n        case .customCharacterClass(let characterClass):\n            return .node(\n                FlowNode(\n                    style: .characterClass,\n                    label: sourceText(for: characterClass.location) ?? \"[...]\"\n                )\n            )\n\n        case .absentFunction(let absentFunction):\n            return .node(\n                FlowNode(\n                    style: .special,\n                    label: sourceText(for: absentFunction.location) ?? \"(?~...)\"\n                )\n            )\n\n        case .empty:\n            return .empty\n        }\n    }\n\n    private mutating func semanticComponent(from node: AST.Node) -> FlowComponent? {\n        let component = component(from: node)\n        if case .empty = component {\n            return nil\n        }\n        return component\n    }\n\n    private mutating func branch(from node: AST.Node) -> [FlowComponent] {\n        let resolved = component(from: node)\n        switch resolved {\n        case .sequence(let children):\n            return children.isEmpty ? [.empty] : children\n        case .empty:\n            return [.empty]\n        default:\n            return [resolved]\n        }\n    }\n\n    private func normalizedSequence(_ components: [FlowComponent]) -> FlowComponent {\n        let flattened = components.flatMap { component -> [FlowComponent] in\n            switch component {\n            case .sequence(let children):\n                return children\n            case .empty:\n                return []\n            default:\n                return [component]\n            }\n        }\n        let compacted = mergeContinuousLiteralNodes(in: flattened)\n\n        switch compacted.count {\n        case 0:\n            return .empty\n        case 1:\n            return compacted[0]\n        default:\n            return .sequence(compacted)\n        }\n    }\n\n    private func mergeContinuousLiteralNodes(in components: [FlowComponent]) -> [FlowComponent] {\n        var merged = [FlowComponent]()\n\n        for component in components {\n            guard case .node(let node) = component, node.style == .literal else {\n                merged.append(component)\n                continue\n            }\n\n            if let last = merged.last, case .node(let previous) = last, previous.style == .literal {\n                merged.removeLast()\n                merged.append(\n                    .node(\n                        FlowNode(\n                            style: .literal,\n                            label: previous.label + node.label\n                        )\n                    )\n                )\n            } else {\n                merged.append(component)\n            }\n        }\n\n        return merged\n    }\n\n    private func quantifier(for quantification: AST.Quantification) -> FlowQuantifier {\n        let label: String\n        if let sourceLabel = sourceText(\n            from: quantification.amount.location.start,\n            to: quantification.location.end\n        ) {\n            label = sourceLabel\n        } else {\n            let amount: String\n            switch quantification.amount.value {\n            case .zeroOrMore:\n                amount = \"*\"\n            case .oneOrMore:\n                amount = \"+\"\n            case .zeroOrOne:\n                amount = \"?\"\n            case .exactly(let number):\n                amount = \"{\\(number.value ?? 0)}\"\n            case .nOrMore(let number):\n                amount = \"{\\(number.value ?? 0),}\"\n            case .upToN(let number):\n                amount = \"{,\\(number.value ?? 0)}\"\n            case .range(let lower, let upper):\n                amount = \"{\\(lower.value ?? 0),\\(upper.value ?? 0)}\"\n            }\n\n            label = amount + quantification.kind.value.rawValue\n        }\n\n        return FlowQuantifier(\n            label: label,\n            isOptional: isOptional(quantification.amount.value)\n        )\n    }\n\n    private func isOptional(_ amount: AST.Quantification.Amount) -> Bool {\n        switch amount {\n        case .zeroOrMore, .zeroOrOne, .upToN:\n            return true\n        case .range(let lower, _):\n            return (lower.value ?? 0) == 0\n        case .exactly, .nOrMore, .oneOrMore:\n            return false\n        }\n    }\n\n    private func flowNode(for atom: AST.Atom) -> FlowNode {\n        let label = sourceText(for: atom.location) ?? fallbackLabel(for: atom)\n\n        switch atom.kind {\n        case .dot:\n            return FlowNode(style: .wildcard, label: \"Any char\")\n\n        case .caretAnchor:\n            return FlowNode(style: .anchor, label: \"^ Start\")\n\n        case .dollarAnchor:\n            return FlowNode(style: .anchor, label: \"$ End\")\n\n        case .property, .escaped:\n            return FlowNode(style: escapedStyle(for: atom), label: label)\n\n        case .backreference, .subpattern:\n            return FlowNode(style: .special, label: label)\n\n        case .callout, .backtrackingDirective, .changeMatchingOptions:\n            return FlowNode(style: .directive, label: label)\n\n        case .invalid:\n            return FlowNode(style: .invalid, label: label)\n\n        case .char, .scalar, .scalarSequence, .keyboardControl,\n             .keyboardMeta, .keyboardMetaControl, .namedCharacter:\n            return FlowNode(style: .literal, label: label)\n        }\n    }\n\n    private func escapedStyle(for atom: AST.Atom) -> FlowNode.Style {\n        guard case .escaped(let builtin) = atom.kind else {\n            return .characterClass\n        }\n\n        switch builtin {\n        case .wordBoundary, .notWordBoundary:\n            return .assertion\n        case .startOfSubject, .endOfSubjectBeforeNewline,\n             .endOfSubject, .firstMatchingPositionInSubject:\n            return .anchor\n        case .alarm, .escape, .formfeed, .newline,\n             .carriageReturn, .tab, .backspace:\n            return .literal\n        default:\n            return .characterClass\n        }\n    }\n\n    private func fallbackLabel(for atom: AST.Atom) -> String {\n        switch atom.kind {\n        case .char(let character):\n            return String(character)\n        case .scalar(let scalar):\n            return String(scalar.value)\n        case .scalarSequence(let sequence):\n            return sequence.scalarValues.map(String.init).joined()\n        case .property:\n            return \"Property\"\n        case .escaped(let builtin):\n            return \"\\\\\\(builtin.character)\"\n        case .keyboardControl(let character):\n            return \"\\\\C-\\(character)\"\n        case .keyboardMeta(let character):\n            return \"\\\\M-\\(character)\"\n        case .keyboardMetaControl(let character):\n            return \"\\\\M-\\\\C-\\(character)\"\n        case .namedCharacter(let name):\n            return \"\\\\N{\\(name)}\"\n        case .dot:\n            return \".\"\n        case .caretAnchor:\n            return \"^\"\n        case .dollarAnchor:\n            return \"$\"\n        case .backreference:\n            return \"Backreference\"\n        case .subpattern:\n            return \"Subpattern\"\n        case .callout:\n            return \"Callout\"\n        case .backtrackingDirective:\n            return \"Directive\"\n        case .changeMatchingOptions:\n            return \"Options\"\n        case .invalid:\n            return \"Invalid\"\n        }\n    }\n\n    private func style(for kind: AST.Group.Kind) -> FlowNode.Style {\n        switch kind {\n        case .capture, .namedCapture, .balancedCapture:\n            return .capturingGroup\n        case .lookahead, .negativeLookahead, .nonAtomicLookahead,\n             .lookbehind, .negativeLookbehind, .nonAtomicLookbehind:\n            return .assertion\n        case .changeMatchingOptions:\n            return .directive\n        case .scriptRun, .atomicScriptRun:\n            return .special\n        case .nonCapture, .nonCaptureReset, .atomicNonCapturing:\n            return .grouping\n        }\n    }\n\n    private func title(for kind: AST.Group.Kind, captureReference: String?) -> String {\n        let suffix = captureReference.map { \" \\($0)\" } ?? \"\"\n\n        switch kind {\n        case .capture:\n            return \"Group\\(suffix)\"\n        case .namedCapture(let name):\n            return \"Group <\\(name.value)>\\(suffix)\"\n        case .balancedCapture(let balanced):\n            let current = balanced.name?.value ?? \"\"\n            return \"Group <\\(current)-\\(balanced.priorName.value)>\\(suffix)\"\n        case .nonCapture:\n            return \"Group\"\n        case .nonCaptureReset:\n            return \"Branch Reset Group\"\n        case .atomicNonCapturing:\n            return \"Atomic Group\"\n        case .lookahead:\n            return \"Lookahead\"\n        case .negativeLookahead:\n            return \"Negative Lookahead\"\n        case .nonAtomicLookahead:\n            return \"Non-atomic Lookahead\"\n        case .lookbehind:\n            return \"Lookbehind\"\n        case .negativeLookbehind:\n            return \"Negative Lookbehind\"\n        case .nonAtomicLookbehind:\n            return \"Non-atomic Lookbehind\"\n        case .scriptRun:\n            return \"Script Run\"\n        case .atomicScriptRun:\n            return \"Atomic Script Run\"\n        case .changeMatchingOptions:\n            return \"Scoped Options\"\n        }\n    }\n\n    private mutating func nextCaptureReference(for kind: AST.Group.Kind) -> String? {\n        switch kind {\n        case .capture, .namedCapture, .balancedCapture:\n            captureGroupIndex += 1\n            return \"$\\(captureGroupIndex)\"\n        default:\n            return nil\n        }\n    }\n\n    private func conditionLabel(for condition: AST.Conditional.Condition) -> String {\n        switch condition.kind {\n        case .groupMatched:\n            return \"if group matched\"\n        case .recursionCheck:\n            return \"if recursion\"\n        case .groupRecursionCheck:\n            return \"if group recursion\"\n        case .defineGroup:\n            return \"define group\"\n        case .pcreVersionCheck:\n            return \"if PCRE version\"\n        case .group:\n            return \"if nested pattern\"\n        }\n    }\n\n    private func sourceText(for location: SourceLocation) -> String? {\n        sourceText(from: location.start, to: location.end)\n    }\n\n    private func sourceText(from start: String.Index, to end: String.Index) -> String? {\n        guard start >= source.startIndex,\n              end <= source.endIndex,\n              start <= end else {\n            return nil\n        }\n\n        return String(source[start..<end])\n    }\n}\n\nprivate struct FlowPatternBreakdownBuilder {\n    let source: String\n\n    func build() -> FlowPatternBreakdown {\n        let ast = parseWithRecovery(source, .traditional)\n        let catalog = CheatSheetCatalog.shared\n        var collector = FlowPatternBreakdownCollector(source: source, catalog: catalog)\n\n        if let globalOptions = ast.globalOptions {\n            globalOptions.options.forEach { option in\n                collector.collectGlobalOption(option)\n            }\n        }\n\n        collector.collect(from: ast.root)\n        return collector.result\n    }\n}\n\nprivate struct FlowPatternBreakdown {\n    let metacharacters: [FlowCheatSheetMatch]\n    let operators: [FlowCheatSheetMatch]\n\n    var hasItems: Bool {\n        !metacharacters.isEmpty || !operators.isEmpty\n    }\n}\n\nprivate struct FlowCheatSheetMatch: Hashable {\n    let id: String\n    let title: String\n    let description: String\n}\n\nprivate enum FlowCheatSheetKey: String {\n    case alarm\n    case startOfInput\n    case wordBoundary\n    case backspaceInSet\n    case notWordBoundary\n    case controlCharacter\n    case decimalDigit\n    case notDecimalDigit\n    case escapeCharacter\n    case quoteEnd\n    case formFeed\n    case previousMatchEnd\n    case newline\n    case namedCharacter\n    case unicodeProperty\n    case unicodePropertyInverted\n    case quoteStart\n    case carriageReturn\n    case whitespace\n    case notWhitespace\n    case tab\n    case unicodeScalar4\n    case unicodeScalar8\n    case wordCharacter\n    case notWordCharacter\n    case hexScalarBraced\n    case hexScalar2\n    case graphemeCluster\n    case endOfInputBeforeNewline\n    case endOfInput\n    case backreference\n    case octalScalar\n    case customCharacterClass\n    case wildcard\n    case lineStart\n    case lineEnd\n    case escapedLiteral\n    case alternation\n    case zeroOrMore\n    case oneOrMore\n    case zeroOrOne\n    case exactlyN\n    case nOrMore\n    case range\n    case zeroOrMoreReluctant\n    case oneOrMoreReluctant\n    case zeroOrOneReluctant\n    case exactlyNReluctant\n    case nOrMoreReluctant\n    case rangeReluctant\n    case zeroOrMorePossessive\n    case oneOrMorePossessive\n    case zeroOrOnePossessive\n    case exactlyNPossessive\n    case nOrMorePossessive\n    case rangePossessive\n    case capturingGroup\n    case nonCapturingGroup\n    case atomicGroup\n    case commentGroup\n    case lookahead\n    case negativeLookahead\n    case lookbehind\n    case negativeLookbehind\n    case scopedOptionChange\n    case inlineOptionChange\n}\n\nprivate struct CheatSheetCatalog {\n    static let shared = CheatSheetCatalog.load()\n\n    let metacharacters: [FlowCheatSheetKey: CheatSheetPlist.Item]\n    let operators: [FlowCheatSheetKey: CheatSheetPlist.Item]\n\n    func metacharacter(for key: FlowCheatSheetKey) -> CheatSheetPlist.Item? {\n        metacharacters[key]\n    }\n\n    func operatorItem(for key: FlowCheatSheetKey) -> CheatSheetPlist.Item? {\n        operators[key]\n    }\n\n    private static func load() -> CheatSheetCatalog {\n        let plist = CheatSheetPlist.localizedCheatSheet ?? CheatSheetPlist(metacharacters: [], operators: [])\n\n        let metacharacters = Dictionary(\n            uniqueKeysWithValues: plist.metacharacters.compactMap { item -> (FlowCheatSheetKey, CheatSheetPlist.Item)? in\n                guard let key = metacharacterKey(for: item.exp, description: item.des) else {\n                    return nil\n                }\n                return (key, item)\n            }\n        )\n\n        let operators = Dictionary(\n            uniqueKeysWithValues: plist.operators.compactMap { item -> (FlowCheatSheetKey, CheatSheetPlist.Item)? in\n                guard let key = operatorKey(for: item.exp) else {\n                    return nil\n                }\n                return (key, item)\n            }\n        )\n\n        return CheatSheetCatalog(metacharacters: metacharacters, operators: operators)\n    }\n\n    private static func metacharacterKey(for expression: String, description: String) -> FlowCheatSheetKey? {\n        switch expression {\n        case \"\\\\a\": return .alarm\n        case \"\\\\A\": return .startOfInput\n        case \"\\\\b, outside of a [Set]\": return .wordBoundary\n        case \"\\\\b, within a [Set]\": return .backspaceInSet\n        case \"\\\\B\": return .notWordBoundary\n        case \"\\\\cX\": return .controlCharacter\n        case \"\\\\d\": return .decimalDigit\n        case \"\\\\D\": return .notDecimalDigit\n        case \"\\\\e\": return .escapeCharacter\n        case \"\\\\E\": return .quoteEnd\n        case \"\\\\f\": return .formFeed\n        case \"\\\\G\": return .previousMatchEnd\n        case \"\\\\n\":\n            return description.contains(\"Back Reference\") ? .backreference : .newline\n        case \"\\\\N{UNICODE CHARACTER NAME}\": return .namedCharacter\n        case \"\\\\p{UNICODE PROPERTY NAME}\": return .unicodeProperty\n        case \"\\\\P{UNICODE PROPERTY NAME}\": return .unicodePropertyInverted\n        case \"\\\\Q\": return .quoteStart\n        case \"\\\\r\": return .carriageReturn\n        case \"\\\\s\": return .whitespace\n        case \"\\\\S\": return .notWhitespace\n        case \"\\\\t\": return .tab\n        case \"\\\\uhhhh\": return .unicodeScalar4\n        case \"\\\\Uhhhhhhhh\": return .unicodeScalar8\n        case \"\\\\w\": return .wordCharacter\n        case \"\\\\W\": return .notWordCharacter\n        case \"\\\\x{hhhh}\": return .hexScalarBraced\n        case \"\\\\xhh\": return .hexScalar2\n        case \"\\\\X\": return .graphemeCluster\n        case \"\\\\Z\": return .endOfInputBeforeNewline\n        case \"\\\\z\": return .endOfInput\n        case \"\\\\0ooo\": return .octalScalar\n        case \"[pattern]\": return .customCharacterClass\n        case \".\": return .wildcard\n        case \"^\": return .lineStart\n        case \"$\": return .lineEnd\n        case \"\\\\\": return .escapedLiteral\n        default: return nil\n        }\n    }\n\n    private static func operatorKey(for expression: String) -> FlowCheatSheetKey? {\n        switch expression {\n        case \"|\": return .alternation\n        case \"*\": return .zeroOrMore\n        case \"+\": return .oneOrMore\n        case \"?\": return .zeroOrOne\n        case \"{n}\": return .exactlyN\n        case \"{n,}\": return .nOrMore\n        case \"{n,m}\": return .range\n        case \"*?\": return .zeroOrMoreReluctant\n        case \"+?\": return .oneOrMoreReluctant\n        case \"??\": return .zeroOrOneReluctant\n        case \"{n}?\": return .exactlyNReluctant\n        case \"{n,}?\": return .nOrMoreReluctant\n        case \"{n,m}?\": return .rangeReluctant\n        case \"*+\": return .zeroOrMorePossessive\n        case \"++\": return .oneOrMorePossessive\n        case \"?+\": return .zeroOrOnePossessive\n        case \"{n}+\": return .exactlyNPossessive\n        case \"{n,}+\": return .nOrMorePossessive\n        case \"{n,m}+\": return .rangePossessive\n        case \"(...)\": return .capturingGroup\n        case \"(?:...)\": return .nonCapturingGroup\n        case \"(?>...)\": return .atomicGroup\n        case \"(?# ... )\": return .commentGroup\n        case \"(?= ... )\": return .lookahead\n        case \"(?! ... )\": return .negativeLookahead\n        case \"(?<= ... )\": return .lookbehind\n        case \"(?<! ... )\": return .negativeLookbehind\n        case \"(?ismwx-ismwx: ... )\": return .scopedOptionChange\n        case \"(?ismwx-ismwx)\": return .inlineOptionChange\n        default: return nil\n        }\n    }\n}\n\nprivate struct FlowPatternBreakdownCollector {\n    let source: String\n    let catalog: CheatSheetCatalog\n\n    private(set) var metacharacters = [FlowCheatSheetMatch]()\n    private(set) var operators = [FlowCheatSheetMatch]()\n    private var seenMetacharacters = Set<String>()\n    private var seenOperators = Set<String>()\n\n    init(source: String, catalog: CheatSheetCatalog) {\n        self.source = source\n        self.catalog = catalog\n    }\n\n    var result: FlowPatternBreakdown {\n        FlowPatternBreakdown(metacharacters: metacharacters, operators: operators)\n    }\n\n    mutating func collect(from node: AST.Node) {\n        switch node {\n        case .alternation(let alternation):\n            addOperator(.alternation)\n            alternation.children.forEach { collect(from: $0) }\n\n        case .concatenation(let concatenation):\n            concatenation.children.forEach { collect(from: $0) }\n\n        case .group(let group):\n            collect(group)\n\n        case .conditional(let conditional):\n            collect(condition: conditional.condition)\n            collect(from: conditional.trueBranch)\n            collect(from: conditional.falseBranch)\n\n        case .quantification(let quantification):\n            addOperator(quantifierSignature(for: quantification))\n            collect(from: quantification.child)\n\n        case .quote:\n            addMetacharacter(.quoteStart)\n            addMetacharacter(.quoteEnd)\n\n        case .trivia(let trivia):\n            if sourceText(for: trivia.location)?.hasPrefix(\"(?#\") == true {\n                addOperator(.commentGroup)\n            }\n\n        case .interpolation:\n            break\n\n        case .atom(let atom):\n            collect(atom)\n\n        case .customCharacterClass(let characterClass):\n            addMetacharacter(.customCharacterClass)\n            characterClass.members.forEach { collect(characterClassMember: $0) }\n\n        case .absentFunction, .empty:\n            break\n        }\n    }\n\n    mutating func collectGlobalOption(_ option: AST.GlobalMatchingOption) {\n        addOperator(.inlineOptionChange, display: sourceText(for: option.location))\n    }\n\n    private mutating func collect(_ group: AST.Group) {\n        switch group.kind.value {\n        case .capture, .namedCapture, .balancedCapture:\n            addOperator(.capturingGroup)\n        case .nonCapture, .nonCaptureReset:\n            addOperator(.nonCapturingGroup)\n        case .atomicNonCapturing:\n            addOperator(.atomicGroup)\n        case .lookahead, .nonAtomicLookahead:\n            addOperator(.lookahead)\n        case .negativeLookahead:\n            addOperator(.negativeLookahead)\n        case .lookbehind, .nonAtomicLookbehind:\n            addOperator(.lookbehind)\n        case .negativeLookbehind:\n            addOperator(.negativeLookbehind)\n        case .changeMatchingOptions:\n            addOperator(.scopedOptionChange, display: sourceText(for: group.location))\n        case .scriptRun, .atomicScriptRun:\n            break\n        }\n\n        collect(from: group.child)\n    }\n\n    private mutating func collect(condition: AST.Conditional.Condition) {\n        if case .group(let group) = condition.kind {\n            collect(group)\n        }\n    }\n\n    private mutating func collect(_ atom: AST.Atom) {\n        let text = sourceText(for: atom.location)\n\n        switch atom.kind {\n        case .char:\n            if text?.hasPrefix(\"\\\\\") == true {\n                addMetacharacter(.escapedLiteral, display: text)\n            }\n        case .scalar:\n            if let text {\n                if text.hasPrefix(\"\\\\u\") {\n                    addMetacharacter(.unicodeScalar4, display: text)\n                } else if text.hasPrefix(\"\\\\U\") {\n                    addMetacharacter(.unicodeScalar8, display: text)\n                } else if text.hasPrefix(\"\\\\x{\") {\n                    addMetacharacter(.hexScalarBraced, display: text)\n                } else if text.hasPrefix(\"\\\\x\") {\n                    addMetacharacter(.hexScalar2, display: text)\n                } else if text.hasPrefix(\"\\\\0\") {\n                    addMetacharacter(.octalScalar, display: text)\n                }\n            }\n        case .scalarSequence:\n            addMetacharacter(.hexScalarBraced, display: text)\n        case .property(let property):\n            addMetacharacter(property.isInverted ? .unicodePropertyInverted : .unicodeProperty, display: text)\n        case .escaped(let builtin):\n            collectEscapedBuiltin(builtin, display: text)\n        case .keyboardControl:\n            addMetacharacter(.controlCharacter, display: text)\n        case .keyboardMeta, .keyboardMetaControl:\n            break\n        case .namedCharacter:\n            addMetacharacter(.namedCharacter, display: text)\n        case .dot:\n            addMetacharacter(.wildcard, display: text)\n        case .caretAnchor:\n            addMetacharacter(.lineStart, display: text)\n        case .dollarAnchor:\n            addMetacharacter(.lineEnd, display: text)\n        case .backreference:\n            addMetacharacter(.backreference, display: text)\n        case .subpattern:\n            break\n        case .callout, .backtrackingDirective:\n            break\n        case .changeMatchingOptions:\n            addOperator(.inlineOptionChange, display: text)\n        case .invalid:\n            break\n        }\n    }\n\n    private mutating func collectEscapedBuiltin(_ builtin: AST.Atom.EscapedBuiltin, display: String?) {\n        switch builtin {\n        case .alarm: addMetacharacter(.alarm, display: display)\n        case .escape: addMetacharacter(.escapeCharacter, display: display)\n        case .formfeed: addMetacharacter(.formFeed, display: display)\n        case .newline: addMetacharacter(.newline, display: display)\n        case .carriageReturn: addMetacharacter(.carriageReturn, display: display)\n        case .tab: addMetacharacter(.tab, display: display)\n        case .decimalDigit: addMetacharacter(.decimalDigit, display: display)\n        case .notDecimalDigit: addMetacharacter(.notDecimalDigit, display: display)\n        case .whitespace: addMetacharacter(.whitespace, display: display)\n        case .notWhitespace: addMetacharacter(.notWhitespace, display: display)\n        case .wordCharacter: addMetacharacter(.wordCharacter, display: display)\n        case .notWordCharacter: addMetacharacter(.notWordCharacter, display: display)\n        case .graphemeCluster: addMetacharacter(.graphemeCluster, display: display)\n        case .wordBoundary: addMetacharacter(.wordBoundary, display: display)\n        case .notWordBoundary: addMetacharacter(.notWordBoundary, display: display)\n        case .startOfSubject: addMetacharacter(.startOfInput, display: display)\n        case .endOfSubjectBeforeNewline: addMetacharacter(.endOfInputBeforeNewline, display: display)\n        case .endOfSubject: addMetacharacter(.endOfInput, display: display)\n        case .firstMatchingPositionInSubject: addMetacharacter(.previousMatchEnd, display: display)\n        case .backspace: addMetacharacter(.backspaceInSet, display: display)\n        case .singleDataUnit, .horizontalWhitespace, .notHorizontalWhitespace,\n             .notNewline, .newlineSequence, .verticalTab, .notVerticalTab,\n             .resetStartOfMatch, .trueAnychar, .textSegment, .notTextSegment:\n            break\n        }\n    }\n\n    private mutating func collect(characterClassMember member: AST.CustomCharacterClass.Member) {\n        switch member {\n        case .custom(let characterClass):\n            addMetacharacter(.customCharacterClass)\n            characterClass.members.forEach { collect(characterClassMember: $0) }\n        case .range(let range):\n            collect(range.lhs)\n            collect(range.rhs)\n        case .atom(let atom):\n            collect(atom)\n        case .quote:\n            addMetacharacter(.quoteStart)\n            addMetacharacter(.quoteEnd)\n        case .trivia:\n            break\n        case .setOperation(let lhs, _, let rhs):\n            lhs.forEach { collect(characterClassMember: $0) }\n            rhs.forEach { collect(characterClassMember: $0) }\n        }\n    }\n\n    private func quantifierSignature(for quantification: AST.Quantification) -> FlowCheatSheetKey {\n        switch (quantification.amount.value, quantification.kind.value) {\n        case (.zeroOrMore, .eager): return .zeroOrMore\n        case (.oneOrMore, .eager): return .oneOrMore\n        case (.zeroOrOne, .eager): return .zeroOrOne\n        case (.exactly, .eager): return .exactlyN\n        case (.nOrMore, .eager): return .nOrMore\n        case (.range, .eager), (.upToN, .eager): return .range\n        case (.zeroOrMore, .reluctant): return .zeroOrMoreReluctant\n        case (.oneOrMore, .reluctant): return .oneOrMoreReluctant\n        case (.zeroOrOne, .reluctant): return .zeroOrOneReluctant\n        case (.exactly, .reluctant): return .exactlyNReluctant\n        case (.nOrMore, .reluctant): return .nOrMoreReluctant\n        case (.range, .reluctant), (.upToN, .reluctant): return .rangeReluctant\n        case (.zeroOrMore, .possessive): return .zeroOrMorePossessive\n        case (.oneOrMore, .possessive): return .oneOrMorePossessive\n        case (.zeroOrOne, .possessive): return .zeroOrOnePossessive\n        case (.exactly, .possessive): return .exactlyNPossessive\n        case (.nOrMore, .possessive): return .nOrMorePossessive\n        case (.range, .possessive), (.upToN, .possessive): return .rangePossessive\n        }\n    }\n\n    private mutating func addMetacharacter(_ key: FlowCheatSheetKey, display: String? = nil) {\n        guard let item = catalog.metacharacter(for: key),\n              seenMetacharacters.insert(key.rawValue).inserted else {\n            return\n        }\n\n        metacharacters.append(\n            FlowCheatSheetMatch(\n                id: key.rawValue,\n                title: display ?? item.exp,\n                description: item.des\n            )\n        )\n    }\n\n    private mutating func addOperator(_ key: FlowCheatSheetKey, display: String? = nil) {\n        guard let item = catalog.operatorItem(for: key),\n              seenOperators.insert(key.rawValue).inserted else {\n            return\n        }\n\n        operators.append(\n            FlowCheatSheetMatch(\n                id: key.rawValue,\n                title: display ?? item.exp,\n                description: item.des\n            )\n        )\n    }\n\n    private func sourceText(for location: SourceLocation) -> String? {\n        guard location.start >= source.startIndex,\n              location.end <= source.endIndex,\n              location.start <= location.end else {\n            return nil\n        }\n\n        return String(source[location.start..<location.end])\n    }\n}\n\nprivate indirect enum FlowComponent {\n    case node(FlowNode)\n    case group(FlowGroup)\n    case sequence([FlowComponent])\n    case alternation([[FlowComponent]])\n    case quantified(FlowComponent, FlowQuantifier)\n    case empty\n}\n\nprivate struct FlowQuantifier {\n    let label: String\n    let isOptional: Bool\n}\n\nprivate struct FlowNode {\n    enum Style: Equatable {\n        case literal\n        case characterClass\n        case capturingGroup\n        case grouping\n        case assertion\n        case anchor\n        case wildcard\n        case directive\n        case special\n        case invalid\n    }\n\n    let style: Style\n    let label: String\n}\n\nprivate struct FlowGroup {\n    let style: FlowNode.Style\n    let title: String\n    let content: FlowComponent\n}\n\nprivate struct FlowDiagramView: View {\n    let component: FlowComponent\n\n    var body: some View {\n        FlowComponentView(component: component)\n            .fixedSize(horizontal: true, vertical: true)\n    }\n}\n\nprivate struct FlowComponentView: View {\n    let component: FlowComponent\n    var borderStyle: FlowBorderStyle = .solid\n\n    var body: some View {\n        switch component {\n        case .node(let node):\n            NodeView(node: node, borderStyle: borderStyle)\n\n        case .group(let group):\n            GroupView(group: group, borderStyle: borderStyle)\n\n        case .sequence(let components):\n            FlowSequenceView(components: components)\n\n        case .alternation(let branches):\n            AlternationView(branches: branches)\n\n        case .quantified(let child, let quantifier):\n            QuantifiedFlowView(\n                component: child,\n                quantifier: quantifier,\n                borderStyle: child.supportsBorderStyling && quantifier.isOptional ? .dashed : .solid\n            )\n\n        case .empty:\n            NodeView(node: FlowNode(style: .special, label: \"Empty\"), borderStyle: borderStyle)\n        }\n    }\n}\n\nprivate struct PatternBreakdownView: View {\n    let breakdown: FlowPatternBreakdown\n\n    var body: some View {\n        VStack(alignment: .leading, spacing: 12) {\n            if !breakdown.metacharacters.isEmpty {\n                PatternBreakdownSectionView(\n                    title: \"Metacharacters\",\n                    items: breakdown.metacharacters\n                )\n            }\n\n            if !breakdown.operators.isEmpty {\n                PatternBreakdownSectionView(\n                    title: \"Operators\",\n                    items: breakdown.operators\n                )\n            }\n        }\n        .frame(maxWidth: .infinity, alignment: .leading)\n    }\n}\n\nprivate struct PatternBreakdownSectionView: View {\n    let title: LocalizedStringKey\n    let items: [FlowCheatSheetMatch]\n\n    var body: some View {\n        let tokenColumnWidth: CGFloat = 112\n        VStack(alignment: .leading, spacing: 6) {\n            Text(title)\n                .font(.caption.weight(.semibold))\n                .foregroundStyle(FlowPalette.sectionLabel)\n                .textCase(.uppercase)\n                .tracking(1.2)\n\n            VStack(alignment: .leading, spacing: 0) {\n                ForEach(Array(items.enumerated()), id: \\.element.id) { index, item in\n                    HStack(alignment: .center, spacing: 14) {\n                        Text(verbatim: item.title)\n                            .font(.callout.monospaced().weight(.semibold))\n                            .foregroundStyle(FlowPalette.ink)\n                            .lineLimit(2)\n                            .minimumScaleFactor(0.7)\n                            .multilineTextAlignment(.center)\n                            .frame(width: tokenColumnWidth)\n                            .frame(minHeight: 42)\n                            .background(\n                                RoundedRectangle(cornerRadius: 12, style: .continuous)\n                                    .fill(FlowPalette.tokenBoxFill)\n                                    .overlay(\n                                        RoundedRectangle(cornerRadius: 12, style: .continuous)\n                                            .stroke(FlowPalette.tokenBoxBorder, lineWidth: 1)\n                                    )\n                            )\n\n                        Text(verbatim: item.description)\n                            .font(.subheadline)\n                            .foregroundStyle(FlowPalette.secondaryText)\n                            .fixedSize(horizontal: false, vertical: true)\n                            .frame(maxWidth: .infinity, alignment: .leading)\n                    }\n                    .frame(maxWidth: .infinity, alignment: .leading)\n                    .padding(.vertical, 10)\n\n                    if index < items.count - 1 {\n                        Divider()\n                    }\n                }\n            }\n        }\n    }\n}\n\nprivate struct FlowSequenceView: View {\n    let components: [FlowComponent]\n\n    var body: some View {\n        HStack(alignment: .center, spacing: 0) {\n            ForEach(Array(components.enumerated()), id: \\.offset) { index, component in\n                if index > 0 {\n                    Spacer(minLength: 6)\n                    Image(systemName: \"arrow.right\")\n                        .font(.caption2.weight(.semibold))\n                        .foregroundStyle(FlowPalette.connector)\n                        .frame(width: 14)\n                    Spacer(minLength: 6)\n                }\n\n                FlowComponentView(component: component)\n            }\n        }\n        .frame(maxWidth: .infinity, alignment: .center)\n    }\n}\n\nprivate struct AlternationView: View {\n    let branches: [[FlowComponent]]\n\n    var body: some View {\n        VStack(alignment: .center, spacing: 8) {\n            ForEach(Array(branches.enumerated()), id: \\.offset) { index, branch in\n                if index > 0 {\n                    FlowAlternationDivider()\n                }\n\n                FlowSequenceView(components: branch)\n            }\n        }\n        .frame(maxWidth: .infinity, alignment: .center)\n        .padding(.vertical, 2)\n    }\n}\n\nprivate struct GroupView: View {\n    let group: FlowGroup\n    let borderStyle: FlowBorderStyle\n\n    var body: some View {\n        VStack(alignment: .center, spacing: 8) {\n            Text(group.title.uppercased())\n                .font(.caption.weight(.bold))\n                .tracking(1.6)\n                .foregroundStyle(titleColor)\n                .multilineTextAlignment(.center)\n                .frame(maxWidth: .infinity, alignment: .center)\n\n            VStack(alignment: .center, spacing: 8) {\n                FlowComponentView(component: group.content)\n            }\n            .frame(maxWidth: .infinity, alignment: .center)\n        }\n        .padding(.horizontal, 10)\n        .padding(.vertical, 10)\n        .overlay(\n            RoundedRectangle(cornerRadius: 18, style: .continuous)\n                .stroke(borderColor, style: borderStyle.strokeStyle(lineWidth: 1.5))\n        )\n    }\n\n    private var borderColor: Color {\n        styleColor(for: group.style).opacity(0.28)\n    }\n\n    private var titleColor: Color {\n        styleColor(for: group.style)\n    }\n}\n\nprivate struct QuantifiedFlowView: View {\n    let component: FlowComponent\n    let quantifier: FlowQuantifier\n    let borderStyle: FlowBorderStyle\n\n    var body: some View {\n        VStack(spacing: 2) {\n            FlowComponentView(component: component, borderStyle: borderStyle)\n\n            Text(quantifier.label)\n                .font(.caption2.monospaced())\n                .foregroundStyle(quantifierColor)\n        }\n    }\n\n    private var quantifierColor: Color {\n        if quantifier.label.contains(\"?\") {\n            return FlowPalette.quantifierSecondary\n        }\n        return FlowPalette.quantifierPrimary\n    }\n}\n\nprivate struct NodeView: View {\n    let node: FlowNode\n    let borderStyle: FlowBorderStyle\n\n    var body: some View {\n        Text(node.label)\n            .font(.system(size: 13, weight: .semibold, design: .monospaced))\n            .lineLimit(1)\n            .foregroundStyle(labelColor)\n            .frame(minWidth: 40, minHeight: 40)\n            .padding(.horizontal, 8)\n            .background(\n                RoundedRectangle(cornerRadius: 10, style: .continuous)\n                    .fill(fillColor)\n                    .overlay(\n                        RoundedRectangle(cornerRadius: 10, style: .continuous)\n                            .stroke(borderColor, style: borderStyle.strokeStyle(lineWidth: 1))\n                    )\n            )\n            .fixedSize()\n    }\n\n    private var fillColor: Color {\n        if isEndpoint {\n            return FlowPalette.endpointFill\n        }\n        return FlowPalette.nodeFill\n    }\n\n    private var borderColor: Color {\n        if isEndpoint {\n            return FlowPalette.endpointBorder\n        }\n        return color.opacity(0.28)\n    }\n\n    private var labelColor: Color {\n        FlowPalette.ink\n    }\n\n    private var isEndpoint: Bool {\n        node.style == .anchor && (node.label.contains(\"Start\") || node.label.contains(\"End\"))\n    }\n\n    private var color: Color {\n        styleColor(for: node.style)\n    }\n}\n\nprivate enum FlowBorderStyle {\n    case solid\n    case dashed\n\n    func strokeStyle(lineWidth: CGFloat) -> StrokeStyle {\n        switch self {\n        case .solid:\n            return StrokeStyle(lineWidth: lineWidth)\n        case .dashed:\n            return StrokeStyle(lineWidth: lineWidth, dash: [6, 4])\n        }\n    }\n}\n\nprivate extension FlowComponent {\n    var supportsBorderStyling: Bool {\n        switch self {\n        case .node, .group:\n            return true\n        case .sequence, .alternation, .quantified, .empty:\n            return false\n        }\n    }\n}\n\nprivate struct FlowAlternationDivider: View {\n    var body: some View {\n        HStack(spacing: 10) {\n            Rectangle()\n                .fill(FlowPalette.divider)\n                .frame(height: 1)\n\n            Text(\"OR\")\n                .font(.caption.weight(.bold))\n                .tracking(1.4)\n                .foregroundStyle(FlowPalette.secondaryText)\n\n            Rectangle()\n                .fill(FlowPalette.divider)\n                .frame(height: 1)\n        }\n        .padding(.horizontal, 6)\n    }\n}\n\nprivate func styleColor(for style: FlowNode.Style) -> Color {\n    switch style {\n    case .literal:\n        return FlowPalette.literal\n    case .characterClass:\n        return FlowPalette.characterClass\n    case .capturingGroup:\n        return FlowPalette.group\n    case .grouping:\n        return FlowPalette.grouping\n    case .assertion:\n        return FlowPalette.assertion\n    case .anchor:\n        return FlowPalette.anchor\n    case .wildcard:\n        return FlowPalette.wildcard\n    case .directive:\n        return FlowPalette.directive\n    case .special:\n        return FlowPalette.special\n    case .invalid:\n        return FlowPalette.invalid\n    }\n}\n\nprivate enum FlowPalette {\n    static let nodeFill = Color(uiColor: .secondarySystemBackground)\n    static let endpointFill = Color.accentColor.opacity(0.18)\n    static let endpointBorder = Color.accentColor.opacity(0.45)\n    static let connector = Color.secondary.opacity(0.45)\n    static let divider = Color.secondary.opacity(0.22)\n    static let ink = Color.primary\n    static let secondaryText = Color.secondary\n    static let sectionLabel = Color.accentColor\n    static let tokenBoxFill = Color(uiColor: .secondarySystemBackground)\n    static let tokenBoxBorder = Color.accentColor.opacity(0.20)\n    static let quantifierPrimary = Color(red: 0.267, green: 0.553, blue: 0.942)\n    static let quantifierSecondary = Color(red: 0.000, green: 0.620, blue: 0.592)\n\n    static let literal = Color(red: 0.430, green: 0.620, blue: 0.920)\n    static let characterClass = Color(red: 0.336, green: 0.700, blue: 0.650)\n    static let group = Color(red: 0.290, green: 0.560, blue: 0.900)\n    static let grouping = Color(red: 0.500, green: 0.620, blue: 0.860)\n    static let assertion = Color(red: 0.396, green: 0.690, blue: 0.880)\n    static let anchor = Color(red: 0.420, green: 0.560, blue: 0.840)\n    static let wildcard = Color(red: 0.290, green: 0.700, blue: 0.820)\n    static let directive = Color(red: 0.510, green: 0.620, blue: 0.920)\n    static let special = Color(red: 0.470, green: 0.650, blue: 0.850)\n    static let invalid = Color(red: 0.650, green: 0.690, blue: 0.760)\n}\n\nprivate extension CheatSheetPlist {\n    static let localizedCheatSheet: CheatSheetPlist? = {\n        guard let url = Bundle.main.url(forResource: \"CheatSheet\", withExtension: \"plist\"),\n              let data = try? Data(contentsOf: url) else {\n            return nil\n        }\n\n        return try? PropertyListDecoder().decode(CheatSheetPlist.self, from: data)\n    }()\n}\n// swiftlint:enable file_length type_body_length cyclomatic_complexity\n"
  },
  {
    "path": "RegEx+/HomeView.swift",
    "content": "//\n//  TabView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/21.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct HomeView: View {\n    @Environment(\\.managedObjectContext) var managedObjectContext\n\n    var body: some View {\n        if #available(iOS 16.0, macOS 13.0, *) {\n            NavigationSplitView {\n                LibraryView()\n            } detail: {\n                Text(verbatim: \"RegEx+\")\n                    .font(.largeTitle)\n            }\n        } else {\n            NavigationView {\n                LibraryView()\n                Text(verbatim: \"RegEx+\")\n                    .font(.largeTitle)\n            }\n            .currentDeviceNavigationViewStyle()\n        }\n    }\n}\n\nprivate extension View {\n    func currentDeviceNavigationViewStyle() -> AnyView {\n#if targetEnvironment(macCatalyst)\n\n        return AnyView(\n            navigationViewStyle(DoubleColumnNavigationViewStyle())\n        )\n\n#else\n            \n            if UIDevice.current.userInterfaceIdiom == .pad {\n                return AnyView(navigationViewStyle(DoubleColumnNavigationViewStyle()))\n            } else {\n                return AnyView(navigationViewStyle(DefaultNavigationViewStyle()))\n            }\n            \n#endif\n    }\n}\n\nstruct ContentView_Previews: PreviewProvider {\n    static var previews: some View {\n        HomeView()\n    }\n}\n"
  },
  {
    "path": "RegEx+/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>RegEx+</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>ITSAppUsesNonExemptEncryption</key>\n\t<false/>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.developer-tools</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>remote-notification</string>\n\t</array>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UIStatusBarTintParameters</key>\n\t<dict>\n\t\t<key>UINavigationBar</key>\n\t\t<dict>\n\t\t\t<key>Style</key>\n\t\t\t<string>UIBarStyleDefault</string>\n\t\t\t<key>Translucent</key>\n\t\t\t<false/>\n\t\t</dict>\n\t</dict>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/Library/LibraryItemView.swift",
    "content": "//\n//  LibraryItemView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/3.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\nimport CoreData\n\n\nstruct LibraryItemView: View, Equatable {\n\n    @ObservedObject var regEx: RegEx\n\n    var body: some View {\n        NavigationLink {\n            EditorView(regEx: regEx)\n                .equatable()\n                .id(regEx.objectID)\n        } label: {\n            VStack(alignment: .leading, spacing: 4) {\n                Text(regEx.name)\n                    .font(.headline)\n\n                if !regEx.raw.isEmpty {\n                    Text(regEx.raw)\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                        .lineLimit(1)\n                }\n            }\n            .frame(minHeight: 50, maxHeight: 200)\n            .paddingVertical()\n        }\n        .isDetailLink(true)\n    }\n\n    static func == (lhs: LibraryItemView, rhs: LibraryItemView) -> Bool {\n        lhs.regEx.objectID == rhs.regEx.objectID\n            && lhs.regEx.name == rhs.regEx.name\n            && lhs.regEx.raw == rhs.regEx.raw\n    }\n}\n\nprivate extension View {\n\n    func paddingVertical() -> AnyView {\n        #if targetEnvironment(macCatalyst)\n        AnyView(padding(.vertical))\n        #else\n        AnyView(self)\n        #endif\n    }\n\n}\n\nstruct LibraryItemView_Previews: PreviewProvider {\n    private static var regEx: RegEx = {\n        var r: RegEx = RegEx(context: DataManager.shared.persistentContainer.viewContext)\n        r.name = \"Dollars\"\n        r.raw = #\"\\$?((\\d+)\\.?(\\d\\d)?)\"#\n        r.sample = \"$100.00 12.50 $10\"\n        r.substitution = \"$3\"\n        return r\n    }()\n    \n    static var previews: some View {\n        NavigationView {\n            List {\n                LibraryItemView(regEx: regEx)\n                LibraryItemView(regEx: regEx)\n                LibraryItemView(regEx: regEx)\n            }\n        }\n        .navigationTitle(Text(verbatim: \"Test\"))\n    }\n}\n"
  },
  {
    "path": "RegEx+/Library/LibraryView+Data.swift",
    "content": "//\n//  LibraryView+Data.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/3.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport CoreData\n\n\nextension LibraryView {\n    \n    func deleteRegEx(indexSet: IndexSet) {\n        let source = indexSet.first!\n        let regEx = regExItems[source]\n        managedObjectContext.delete(regEx)\n        \n        save()\n    }\n    \n    func addRegEx(withSample: Bool) {\n        let regEx = RegEx(context: managedObjectContext)\n\n        if withSample, let randomItem = sampleData().randomElement() {\n            regEx.name = randomItem.name\n            regEx.raw = randomItem.raw\n            regEx.sample = randomItem.sample\n            regEx.allowCommentsAndWhitespace = randomItem.allowComments\n            regEx.createdAt = Date()\n        } else {\n            regEx.name = NSLocalizedString(\"Untitled\", comment: \"Default item name\")\n            regEx.raw = \"\"\n            regEx.createdAt = Date()\n        }\n\n        save()\n        editMode = .inactive\n    }\n    \n    private func save() {\n        DataManager.shared.saveContext()\n    }\n    \n    private func sampleData() -> [SampleItem] {\n        return [\n            SampleItem(\"Dollars\", raw: #\"(\\$[\\d]+)\\.?(\\d{2})?\"#),\n            SampleItem(\"Hex\", raw: #\"#?([a-f0-9]{6}|[a-f0-9]{3})\"#, sample: \"#336699\\n#F2A\\nFF9933\"),\n            SampleItem(\"Allow Comments\", raw: #\"(\\$[\\d]+) # Dollars symbol and digits\"#, allowComments: true),\n            SampleItem(\"Roman Numeral\", raw: #\"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\"#),\n            SampleItem(\"Email\", raw: #\"([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})\"#, sample: \"ive@apple.com\"),\n            SampleItem(\"HTML <li> tag\", raw: #\"<li>(.*?)</li>\"#, sample: \"<li>iPhone</li>\\n<li>iPad</li>\"),\n        ]\n    }\n    \n}\n\nprivate struct SampleItem {\n    let name: String\n    let raw: String\n    let sample: String\n    let allowComments: Bool\n    \n    init(_ name: String, raw: String, sample: String = \"\", allowComments: Bool = false) {\n        self.name = name\n        self.raw = raw\n        self.sample = sample\n        self.allowComments = allowComments\n    }\n}\n"
  },
  {
    "path": "RegEx+/Library/LibraryView.swift",
    "content": "//\n//  LibraryView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/21.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\nimport CoreData\n\n\nstruct LibraryView: View, Equatable {\n\n    static func == (lhs: LibraryView, rhs: LibraryView) -> Bool {\n        lhs.regExItems.map(\\.objectID).hashValue == rhs.regExItems.map(\\.objectID).hashValue\n    }\n\n    @Environment(\\.managedObjectContext) var managedObjectContext\n    @FetchRequest(fetchRequest: RegEx.fetchAllRegEx()) var regExItems: FetchedResults<RegEx>\n\n    @State private var searchTerm = \"\"\n    @State var editMode = EditMode.inactive\n    \n    private var filteredItems: [RegEx] {\n        if searchTerm.isEmpty {\n            return Array(regExItems)\n        }\n        return regExItems.filter { item in\n            item.name.localizedCaseInsensitiveContains(searchTerm) ||\n            item.raw.localizedCaseInsensitiveContains(searchTerm)\n        }\n    }\n\n    var body: some View {\n        VStack(alignment: .leading) {\n            SearchView(text: $searchTerm)\n                .padding(.horizontal)\n\n            if regExItems.isEmpty {\n                VStack(alignment: .center) {\n                    Text(\"Your RegEx+ library is empty\")\n                        .font(.subheadline)\n                        .foregroundStyle(.secondary)\n                    Button {\n                        addRegEx(withSample: true)\n                    } label: {\n                        Text(\"Create a sample\")\n                    }\n                    .buttonStyle(.bordered)\n                }\n                .frame(maxWidth: .greatestFiniteMagnitude, maxHeight: .greatestFiniteMagnitude)\n            } else {\n                List {\n                    ForEach(filteredItems, id: \\.objectID) {\n                        LibraryItemView(regEx: $0).equatable()\n                    }\n                    .onDelete(perform: deleteRegEx)\n                }\n                .currentDeviceListStyle()\n                .environment(\\.editMode, $editMode)\n            }\n        }\n        .navigationTitle(\"RegEx+\")\n        .setNavigationItems(libraryView: self)\n    }\n\n\n    var editButton: some View {\n        Button(action: {\n            editMode = editMode.isEditing ? .inactive : .active\n        }, label: {\n            Text(editMode.isEditing ? \"Done\" : \"Edit\")\n        })\n    }\n    \n    var aboutButton: some View {\n        NavigationLink(destination: AboutView()) {\n            Image(systemName: \"info.circle\")\n                .imageScale(.large)\n        }\n    }\n    \n    var addButton: some View {\n        Button {\n            addRegEx(withSample: false)\n        } label: {\n            Image(systemName: \"plus.circle.fill\")\n                .imageScale(.large)\n        }\n    }\n}\n\nprivate extension View {\n    @ViewBuilder\n    func currentDeviceListStyle() -> some View {\n#if targetEnvironment(macCatalyst)\n        self.listStyle(.plain)\n            .padding(.horizontal)\n#else\n        if #available(iOS 14.0, *) {\n            self.listStyle(.insetGrouped)\n        } else {\n            self.listStyle(.grouped)\n        }\n#endif\n    }\n}\n\nprivate extension View {\n    @ViewBuilder\n    func setNavigationItems(libraryView: LibraryView) -> some View {\n        self.toolbar {\n            ToolbarItem(placement: .topBarLeading) {\n                libraryView.editButton\n            }\n#if targetEnvironment(macCatalyst)\n            ToolbarItem(placement: .topBarTrailing) {\n                HStack {\n                    libraryView.aboutButton\n                    libraryView.addButton\n                }\n            }\n#else\n            ToolbarItem(placement: .topBarTrailing) {\n                libraryView.aboutButton\n            }\n            ToolbarItem(placement: .topBarTrailing) {\n                libraryView.addButton\n                    .padding(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 0))\n            }\n#endif\n        }\n    }\n}\n\n#if DEBUG\nstruct LibraryView_Previews: PreviewProvider {\n    static var previews: some View {\n        NavigationView {\n            LibraryView()\n                .environment(\\.managedObjectContext, DataManager.shared.persistentContainer.viewContext)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "RegEx+/Localizable.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"%@\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@\"\n          }\n        }\n      }\n    },\n    \"%lld matches\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld Treffer\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld coincidencias\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld correspondances\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld corrispondenze\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld マッチ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld개 일치\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld resultaten\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld dopasowań\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld 次匹配\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld 次匹配\"\n          }\n        }\n      }\n    },\n    \"1 match\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1 Treffer\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1 coincidencia\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1 correspondance\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1 corrispondenza\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1マッチ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1개 일치\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1 resultaat\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1 dopasowanie\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"一次匹配\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"一次匹配\"\n          }\n        }\n      }\n    },\n    \"Allow Comments and Whitespace\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kommentare und Leerzeichen erlauben\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir comentarios y espacios en blanco\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser les commentaires et les espaces\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti commenti e spazi\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"コメントと空白を許可\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"주석 및 공백 허용\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reacties en witruimte toestaan\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwalaj na komentarze i białe znaki\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许注释和空格\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許註釋和空格\"\n          }\n        }\n      }\n    },\n    \"Anchors Match Lines\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anker passen zu Zeilen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anclas coinciden con líneas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les ancres correspondent aux lignes\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ancore corrispondono alle righe\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アンカーで行をマッチ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"앵커로 라인 일치\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ankers komen overeen met regels\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kotwice dopasowują linie\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"锚点匹配行\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錨點匹配行\"\n          }\n        }\n      }\n    },\n    \"Case Insensitive\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Groß-/Kleinschreibung ignorieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Insensible a mayúsculas/minúsculas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Insensible à la casse\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora maiuscole/minuscole\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"大文字小文字を区別しない\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"대소문자 구분 안 함\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hoofdletterongevoelig\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoruj wielkość liter\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不区分大小写\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不區分大小寫\"\n          }\n        }\n      }\n    },\n    \"Cheat Sheet\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spickzettel\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hoja de Referencia\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Antisèche\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Guida di Riferimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"チートシート\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"치트 시트\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spiekbriefje\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ściąga\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"小抄\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"小抄\"\n          }\n        }\n      }\n    },\n    \"Copies the substitution result to clipboard\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ersetzungsergebnis in Zwischenablage kopieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copia el resultado de sustitución al portapapeles\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copie le résultat de substitution dans le presse-papiers\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copia il risultato della sostituzione negli appunti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"置換結果をクリップボードにコピー\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"치환 결과를 클립보드에 복사\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopieert het vervangingsresultaat naar het klembord\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopiuje wynik podstawienia do schowka\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"将替换结果复制到剪贴板\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將替換結果複製到剪貼板\"\n          }\n        }\n      }\n    },\n    \"Copy substitution result\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ersetzungsergebnis kopieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copiar resultado de sustitución\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copier le résultat de substitution\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copia risultato di sostituzione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"置換結果をコピー\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"치환 결과 복사\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vervangingsresultaat kopiëren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopiuj wynik podstawienia\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"复制替换结果\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"複製替換結果\"\n          }\n        }\n      }\n    },\n    \"Create a sample\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beispiel erstellen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Crear un ejemplo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Créer un exemple\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Crea un esempio\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"サンプルを作成\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"샘플 만들기\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voorbeeld maken\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utwórz przykład\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新建样例\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新建樣例\"\n          }\n        }\n      }\n    },\n    \"Done\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fertig\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hecho\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terminé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fatto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"完了\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"완료\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gereed\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gotowe\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"完成\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"完成\"\n          }\n        }\n      }\n    },\n    \"Dot Matches Line Separators\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Punkt entspricht Zeilentrenner\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Punto coincide con separadores de línea\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le point correspond aux séparateurs de ligne\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il punto corrisponde ai separatori di riga\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ドットで改行文字をマッチ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"점이 줄 구분 기호와 일치\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Punt komt overeen met regelscheidingstekens\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kropka dopasowuje separatory linii\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"点符号匹配行分隔符\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"點符號匹配行分隔符\"\n          }\n        }\n      }\n    },\n    \"Edit\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bearbeiten\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifier\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifica\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"編集\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"편집\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bewerk\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edytuj\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"编辑\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"編輯\"\n          }\n        }\n      }\n    },\n    \"Enter a regular expression to see the flow diagram\" : {\n\n    },\n    \"Flow Diagram\" : {\n\n    },\n    \"Ignore Metacharacters\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metazeichen ignorieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar metacaracteres\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer les métacaractères\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora metacaratteri\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"メタ文字を無視\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"메타 문자 무시\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metatekens negeren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoruj metaznaki\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略元字符\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略元字符\"\n          }\n        }\n      }\n    },\n    \"Insert %@ into text\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ in Text einfügen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Insertar %@ en texto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Insérer %@ dans le texte\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inserisci %@ nel testo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@をテキストに挿入\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@를 텍스트에 삽입\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voeg %@ in tekst in\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wstaw %@ do tekstu\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"将%@插入文本\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將%@插入文字\"\n          }\n        }\n      }\n    },\n    \"Loading...\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Laden...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cargando...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chargement...\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Caricamento...\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"読み込み中...\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"로드 중...\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Laden...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ładowanie...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加载中...\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"載入中...\"\n          }\n        }\n      }\n    },\n    \"Metacharacters\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metazeichen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metacaracteres\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Métacaractères\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metacaratteri\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"メタ文字\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"메타 문자\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metatekens\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Metaznaki\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"元字符\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"元字符\"\n          }\n        }\n      }\n    },\n    \"Name\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Name\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名前\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이름\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naam\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名字\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名字\"\n          }\n        }\n      }\n    },\n    \"Operators\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Operatoren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Operadores\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opérateurs\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Operatori\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"演算子\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"연산자\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Operatoren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Operatory\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"操作符\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"操作符\"\n          }\n        }\n      }\n    },\n    \"Options\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Optionen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opciones\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Options\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opzioni\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"オプション\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"옵션\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opties\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opcje\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"选项\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選項\"\n          }\n        }\n      }\n    },\n    \"OR\" : {\n\n    },\n    \"Price: $$$1\\\\.$2\\\\n\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Preis: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Precio: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prix : $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prezzo: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"価格: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"가격: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prijs: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cena: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"价格: $$$1\\\\.$2\\\\n\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"價格: $$$1\\\\.$2\\\\n\"\n          }\n        }\n      }\n    },\n    \"RegEx+\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+\"\n          }\n        }\n      }\n    },\n    \"Regular Expression\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regulärer Ausdruck\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Expresión Regular\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Expression Régulière\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espressione Regolare\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正規表現\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"정규 표현식\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguliere expressie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyrażenie regularne\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正则表达式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正則表達式\"\n          }\n        }\n      }\n    },\n    \"Sample Text\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beispieltext\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Texto de Ejemplo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Texte d'Exemple\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Testo di Esempio\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"サンプルテキスト\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"샘플 텍스트\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voorbeeldtekst\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przykładowy tekst\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"示例文字\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"示例文字\"\n          }\n        }\n      }\n    },\n    \"Search...\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suchen...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechercher...\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerca...\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"検索...\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"검색...\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoeken...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szukaj...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"搜索...\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"搜索...\"\n          }\n        }\n      }\n    },\n    \"Share\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teilen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Compartir\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Partager\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Condividi\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"共有\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"공유\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deel\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udostępnij\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分享\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分享\"\n          }\n        }\n      }\n    },\n    \"Share this regular expression\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diesen regulären Ausdruck teilen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Compartir esta expresión regular\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Partager cette expression régulière\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Condividi questa espressione regolare\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"この正規表現を共有\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이 정규 표현식 공유\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deel deze reguliere expressie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udostępnij to wyrażenie regularne\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分享这个正则表达式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分享這個正則表達式\"\n          }\n        }\n      }\n    },\n    \"Substitution Result\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ersetzungsergebnis\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resultado de Sustitución\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Résultat de Substitution\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Risultato di Sostituzione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"置換結果\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"치환 결과\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vervangingsresultaat\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wynik podstawienia\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"替换结果\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"替換結果\"\n          }\n        }\n      }\n    },\n    \"Substitution Template\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ersetzungsvorlage\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plantilla de Sustitución\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modèle de Substitution\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modello di Sostituzione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"置換テンプレート\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"치환 템플릿\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vervangingssjabloon\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szablon podstawienia\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"替换模板\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"替換模板\"\n          }\n        }\n      }\n    },\n    \"Untitled\" : {\n      \"comment\" : \"Default item name\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ohne Titel\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sin título\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sans titre\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Senza titolo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無題\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"제목 없음\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naamloos\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bez tytułu\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未命名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未命名\"\n          }\n        }\n      }\n    },\n    \"Use Unicode Word Boundaries\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unicode-Wortgrenzen verwenden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usar límites de palabra Unicode\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utiliser les limites de mots Unicode\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usa limiti di parola Unicode\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unicode単語境界を使用\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"유니코드 단어 경계 사용\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebruik Unicode-woordgrenzen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Użyj granic słów Unicode\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用 Unicode 字符边界\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用 Unicode 字符邊界\"\n          }\n        }\n      }\n    },\n    \"Use Unix Line Separators\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unix-Zeilentrenner verwenden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usar separadores de línea Unix\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utiliser les séparateurs de ligne Unix\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usa separatori di riga Unix\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unix改行文字を使用\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unix 줄 구분 기호 사용\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebruik Unix-regelscheidingstekens\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Użyj separatorów linii Unix\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用 Unix 换行符\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用 Unix 換行符\"\n          }\n        }\n      }\n    },\n    \"View regular expression reference guide\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regulärer Ausdruck-Referenzhandbuch anzeigen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ver guía de referencia de expresiones regulares\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voir le guide de référence des expressions régulières\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visualizza la guida di riferimento delle espressioni regolari\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正規表現リファレンスガイドを表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"정규 표현식 참조 가이드 보기\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bekijk de referentiegids voor reguliere expressies\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobacz przewodnik po wyrażeniach regularnych\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查看正则表达式参考指南\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查看正則表達式參考指南\"\n          }\n        }\n      }\n    },\n    \"Your RegEx+ library is empty\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ihre RegEx+ Bibliothek ist leer\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tu biblioteca RegEx+ está vacía\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Votre bibliothèque RegEx+ est vide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La tua libreria RegEx+ è vuota\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+ライブラリが空です\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"RegEx+ 라이브러리가 비어 있습니다\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Je RegEx+ bibliotheek is leeg\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Twoja biblioteka RegEx+ jest pusta\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你的 RegEx+ 仓库是空的\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你的 RegEx+ 倉庫是空的\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "RegEx+/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "RegEx+/RegEx+.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>aps-environment</key>\n\t<string>development</string>\n\t<key>com.apple.developer.icloud-container-identifiers</key>\n\t<array>\n\t\t<string>iCloud.RegExCatalyst</string>\n\t</array>\n\t<key>com.apple.developer.icloud-services</key>\n\t<array>\n\t\t<string>CloudKit</string>\n\t</array>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/RegEx.xcdatamodeld/.xccurrentversion",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>_XCCurrentVersionName</key>\n\t<string>RegEx.xcdatamodel</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/RegEx.xcdatamodeld/RegEx.xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"16119\" systemVersion=\"19E287\" minimumToolsVersion=\"Automatic\" sourceLanguage=\"Swift\" userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"RegEx\" representedClassName=\"RegEx\" syncable=\"YES\">\n        <attribute name=\"allowCommentsAndWhitespace\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n        <attribute name=\"anchorsMatchLines\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n        <attribute name=\"caseInsensitive\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n        <attribute name=\"createdAt\" attributeType=\"Date\" defaultDateTimeInterval=\"599504400\" usesScalarValueType=\"NO\"/>\n        <attribute name=\"dotMatchesLineSeparators\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n        <attribute name=\"ignoreMetacharacters\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n        <attribute name=\"name\" optional=\"YES\" attributeType=\"String\" defaultValueString=\"Untitled\"/>\n        <attribute name=\"raw\" optional=\"YES\" attributeType=\"String\"/>\n        <attribute name=\"sample\" attributeType=\"String\" defaultValueString=\"\"/>\n        <attribute name=\"substitution\" attributeType=\"String\" defaultValueString=\"\"/>\n        <attribute name=\"updatedAt\" attributeType=\"Date\" defaultDateTimeInterval=\"599504400\" usesScalarValueType=\"NO\"/>\n        <attribute name=\"useUnicodeWordBoundaries\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n        <attribute name=\"useUnixLineSeparators\" optional=\"YES\" attributeType=\"Boolean\" usesScalarValueType=\"YES\"/>\n    </entity>\n    <configuration name=\"Cloud\" usedWithCloudKit=\"YES\">\n        <memberEntity name=\"RegEx\"/>\n    </configuration>\n    <elements>\n        <element name=\"RegEx\" positionX=\"-63\" positionY=\"-18\" width=\"128\" height=\"238\"/>\n    </elements>\n</model>"
  },
  {
    "path": "RegEx+/SceneDelegate.swift",
    "content": "//\n//  SceneDelegate.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/21.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport UIKit\nimport SwiftUI\n\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n    var window: UIWindow?\n\n    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n\n        // Create the SwiftUI view that provides the window contents.\n        let viewContext = DataManager.shared.persistentContainer.viewContext\n\n        let contentView = HomeView()\n            .environment(\\.managedObjectContext, viewContext)\n\n        // Use a UIHostingController as window root view controller.\n        if let windowScene = scene as? UIWindowScene {\n            let window = UIWindow(windowScene: windowScene)\n            window.rootViewController = UIHostingController(rootView: contentView)\n            self.window = window\n            window.makeKeyAndVisible()\n\n            #if targetEnvironment(macCatalyst)\n            if let titlebar = windowScene.titlebar {\n                titlebar.titleVisibility = .visible\n                titlebar.toolbarStyle = .unified\n            }\n            #endif\n        }\n    }\n\n    func sceneDidDisconnect(_ scene: UIScene) {\n        // Called as the scene is being released by the system.\n        // This occurs shortly after the scene enters the background, or when its session is discarded.\n        // Release any resources associated with this scene that can be re-created the next time the scene connects.\n        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n    }\n\n    func sceneDidBecomeActive(_ scene: UIScene) {\n        // Called when the scene has moved from an inactive state to an active state.\n        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n    }\n\n    func sceneWillResignActive(_ scene: UIScene) {\n        // Called when the scene will move from an active state to an inactive state.\n        // This may occur due to temporary interruptions (ex. an incoming phone call).\n    }\n\n    func sceneWillEnterForeground(_ scene: UIScene) {\n        // Called as the scene transitions from the background to the foreground.\n        // Use this method to undo the changes made on entering the background.\n    }\n\n    func sceneDidEnterBackground(_ scene: UIScene) {\n        // Called as the scene transitions from the foreground to the background.\n        // Use this method to save data, release shared resources, and store enough scene-specific state information\n        // to restore the scene back to its current state.\n    }\n\n\n}\n"
  },
  {
    "path": "RegEx+/Views/ActivityViewController.swift",
    "content": "//\n//  ActivityViewController.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/16.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport UIKit\nimport SwiftUI\n\nstruct ActivityViewController: UIViewControllerRepresentable {\n\n    var activityItems: [Any]\n    var applicationActivities: [UIActivity]?\n\n    func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {\n        let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)\n        return controller\n    }\n\n    func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}\n\n}\n"
  },
  {
    "path": "RegEx+/Views/RegExSyntaxView.swift",
    "content": "//\n//  RegExSyntaxView.swift\n//  RegExPro\n//\n//  Created by Lex on 2020/4/23.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\nimport Combine\nimport UIKit\n\n\nprivate struct UITextViewWrapper: UIViewRepresentable {\n    typealias UIViewType = UITextView\n\n    @Binding var text: String\n    @Binding var calculatedHeight: CGFloat\n    var onDone: (() -> Void)?\n\n    func makeUIView(context: UIViewRepresentableContext<UITextViewWrapper>) -> UITextView {\n        let tv = UITextView()\n        tv.delegate = context.coordinator\n\n        tv.isEditable = true\n        tv.font = UIFont.preferredFont(forTextStyle: .body)\n        tv.isSelectable = true\n        tv.isUserInteractionEnabled = true\n        tv.isScrollEnabled = false\n        tv.backgroundColor = UIColor.clear\n        tv.textContainerInset = .zero\n        tv.textContainer.lineFragmentPadding = 0\n        if nil != onDone {\n            tv.returnKeyType = .done\n        }\n        tv.textStorage.delegate = syntaxHighlighter\n\n        tv.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)\n        return tv\n    }\n\n    func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<UITextViewWrapper>) {\n        if uiView.text != self.text {\n            uiView.text = self.text\n        }\n        if uiView.window != nil, !uiView.isFirstResponder {\n            uiView.becomeFirstResponder()\n        }\n        UITextViewWrapper.recalculateHeight(view: uiView, result: $calculatedHeight)\n    }\n\n    fileprivate static func recalculateHeight(view: UIView, result: Binding<CGFloat>) {\n        let newSize = view.sizeThatFits(CGSize(width: view.frame.size.width, height: CGFloat.greatestFiniteMagnitude))\n        if result.wrappedValue != newSize.height {\n            DispatchQueue.main.async {\n                result.wrappedValue = newSize.height // !! must be called asynchronously\n            }\n        }\n    }\n\n    func makeCoordinator() -> Coordinator {\n        return Coordinator(text: $text, height: $calculatedHeight, onDone: onDone)\n    }\n\n    final class Coordinator: NSObject, UITextViewDelegate {\n        var text: Binding<String>\n        var calculatedHeight: Binding<CGFloat>\n        var onDone: (() -> Void)?\n\n        init(text: Binding<String>, height: Binding<CGFloat>, onDone: (() -> Void)? = nil) {\n            self.text = text\n            self.calculatedHeight = height\n            self.onDone = onDone\n        }\n\n        func textViewDidChange(_ uiView: UITextView) {\n            text.wrappedValue = uiView.text\n            UITextViewWrapper.recalculateHeight(view: uiView, result: calculatedHeight)\n        }\n\n        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {\n            if let onDone = self.onDone, text == \"\\n\" {\n                textView.resignFirstResponder()\n                onDone()\n                return false\n            }\n            return true\n        }\n    }\n    \n    private let syntaxHighlighter = RegExSyntaxHighlighter()\n}\n\nstruct RegExTextView: View {\n\n    private var placeholder: String\n    private var onCommit: (() -> Void)?\n\n    @Binding private var text: String\n    private var internalText: Binding<String> {\n        Binding<String>(get: { self.text }) {\n            self.text = $0\n            self.showingPlaceholder = $0.isEmpty\n        }\n    }\n\n    @State private var dynamicHeight: CGFloat = 100\n    @State private var showingPlaceholder = false\n\n    init (_ placeholder: String = \"\", text: Binding<String>, onCommit: (() -> Void)? = nil) {\n        self.placeholder = placeholder\n        self.onCommit = onCommit\n        self._text = text\n        self._showingPlaceholder = State<Bool>(initialValue: self.text.isEmpty)\n    }\n\n    var body: some View {\n        UITextViewWrapper(text: self.internalText, calculatedHeight: $dynamicHeight, onDone: onCommit)\n            .frame(minHeight: dynamicHeight, maxHeight: dynamicHeight)\n            .background(placeholderView, alignment: .topLeading)\n    }\n\n    var placeholderView: some View {\n        Group {\n            if showingPlaceholder {\n                Text(placeholder).foregroundColor(.gray)\n                    .padding(.leading, 4)\n                    .padding(.top, 8)\n            }\n        }\n    }\n}\n\n#if DEBUG\nstruct MultilineTextField_Previews: PreviewProvider {\n    static var test: String = \"\"\n    static var testBinding = Binding<String>(get: { test }, set: { test = $0 })\n\n    static var previews: some View {\n        VStack(alignment: .leading) {\n            Text(\"Description:\")\n            RegExTextView(\"Enter some text here\", text: testBinding, onCommit: {\n                print(\"Final text: \\(test)\")\n            })\n                .overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.black))\n            Text(\"Something static here...\")\n            Spacer()\n        }\n        .padding()\n    }\n}\n#endif\n\nclass RegExSyntaxHighlighter: NSObject, NSTextStorageDelegate {\n    var fontSize: CGFloat = 16\n    \n    func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {\n        \n        textStorage.addAttributes([\n            .font: UIFont.systemFont(ofSize: fontSize),\n            .foregroundColor: UIColor.black\n        ], range: NSRange(location: 0, length: textStorage.length))\n        \n        textStorage.string.ranges(of: #\"\\\\[$$\\w]\"#, options: .regularExpression).forEach { range in\n            textStorage.addAttributes([\n                .foregroundColor: UIColor.red\n            ], range: textStorage.string.nsRange(from: range))\n        }\n        \n        textStorage.string.ranges(of: #\"[\\(\\)]\"#, options: .regularExpression).forEach { range in\n            textStorage.addAttributes([\n                .foregroundColor: UIColor(red: 0, green: 0.5, blue: 0.2, alpha: 1)\n            ], range: textStorage.string.nsRange(from: range))\n        }\n        \n        textStorage.string.ranges(of: #\"(?:\\{)[\\d,]+(?:\\})\"#, options: .regularExpression).forEach { range in\n            textStorage.addAttributes([\n                .font: UIFont.boldSystemFont(ofSize: fontSize),\n                .foregroundColor: UIColor(red: 0, green: 0.3, blue: 0, alpha: 1)\n            ], range: textStorage.string.nsRange(from: range))\n        }\n        \n        textStorage.string.ranges(of: #\"[\\?\\*\\.]\"#, options: .regularExpression).forEach { range in\n            textStorage.addAttributes([\n                .font: UIFont.boldSystemFont(ofSize: fontSize),\n                .foregroundColor: UIColor(red: 0, green: 0.3, blue: 0, alpha: 1)\n            ], range: textStorage.string.nsRange(from: range))\n        }\n        \n        textStorage.string.ranges(of: #\"[\\^\\[\\$\\]]\"#, options: .regularExpression).forEach { range in\n            textStorage.addAttributes([\n                .foregroundColor: UIColor(red: 0, green: 0, blue: 0.8, alpha: 1)\n            ], range: textStorage.string.nsRange(from: range))\n        }\n        \n    }\n}\n"
  },
  {
    "path": "RegEx+/Views/RegExTextView/MatchesTextView.swift",
    "content": "//\n//  MatchesTextView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/2.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport UIKit\nimport SwiftUI\n\n\nprivate struct MatchesTextViewWrapper: UIViewRepresentable {\n    typealias UIViewType = UITextView\n\n    @Binding var text: String\n    @Binding var calculatedHeight: CGFloat\n    var matches: [NSTextCheckingResult]\n    var onDone: (() -> Void)?\n\n    func makeUIView(context: UIViewRepresentableContext<MatchesTextViewWrapper>) -> UITextView {\n        let tv = UITextView()\n        tv.delegate = context.coordinator\n\n        tv.isEditable = true\n        tv.font = UIFont.preferredFont(forTextStyle: .body)\n        tv.isSelectable = true\n        tv.isUserInteractionEnabled = true\n        tv.isScrollEnabled = false\n        tv.backgroundColor = UIColor.clear\n        \n        tv.textContainerInset = .zero\n        tv.textContainer.lineFragmentPadding = 0\n        if nil != onDone {\n            tv.returnKeyType = .done\n        }\n\n        tv.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)\n        return tv\n    }\n\n    func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<MatchesTextViewWrapper>) {\n        if uiView.attributedText.string != text {\n            uiView.attributedText = NSAttributedString(string: text)\n        }\n\n        if !text.isEmpty {\n            uiView.textStorage.setAttributes([\n                .font: UIFont.preferredFont(forTextStyle: .body),\n                .foregroundColor: UIColor.label\n            ], range: NSRange(location: 0, length: uiView.text.count))\n            \n            matches.forEach { result in\n                for index in 0..<result.numberOfRanges {\n                    let range = result.range(at: index)\n                    if range.location + range.length > uiView.attributedText.length {\n                        return\n                    }\n                    uiView.textStorage.setAttributes([\n                        .font: UIFont.preferredFont(forTextStyle: .body),\n                        .foregroundColor: UIColor.systemBlue\n                    ], range: range)\n                }\n            }\n        }\n        \n        MatchesTextViewWrapper.recalculateHeight(view: uiView, result: $calculatedHeight)\n    }\n\n    fileprivate static func recalculateHeight(view: UIView, result: Binding<CGFloat>) {\n        let newSize = view.sizeThatFits(CGSize(width: view.frame.size.width, height: CGFloat.greatestFiniteMagnitude))\n        if result.wrappedValue != newSize.height {\n            DispatchQueue.main.async {\n                result.wrappedValue = newSize.height // !! must be called asynchronously\n            }\n        }\n    }\n\n    func makeCoordinator() -> Coordinator {\n        return Coordinator(text: $text, height: $calculatedHeight, onDone: onDone)\n    }\n\n    final class Coordinator: NSObject, UITextViewDelegate {\n        var text: Binding<String>\n        var calculatedHeight: Binding<CGFloat>\n        var onDone: (() -> Void)?\n\n        init(text: Binding<String>, height: Binding<CGFloat>, onDone: (() -> Void)? = nil) {\n            self.text = text\n            self.calculatedHeight = height\n            self.onDone = onDone\n        }\n\n        func textViewDidChange(_ uiView: UITextView) {\n            text.wrappedValue = uiView.text\n            MatchesTextViewWrapper.recalculateHeight(view: uiView, result: calculatedHeight)\n        }\n\n        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {\n            if let onDone, text == \"\\n\" {\n                textView.resignFirstResponder()\n                onDone()\n                return false\n            }\n            return true\n        }\n    }\n\n}\n\nstruct MatchesTextView: View, Equatable {\n\n    static func == (lhs: MatchesTextView, rhs: MatchesTextView) -> Bool {\n        lhs.text == rhs.text\n        && lhs.matches == rhs.matches\n    }\n\n    private var placeholder: String\n    private var onCommit: (() -> Void)?\n\n    @Binding private var text: String\n    private var internalText: Binding<String> {\n        Binding<String>(get: { self.text }) {\n            self.text = $0\n            self.showingPlaceholder = $0.isEmpty\n        }\n    }\n    \n    @Binding private var matches: [NSTextCheckingResult]\n    @State private var dynamicHeight: CGFloat = 100\n    @State private var showingPlaceholder = false\n\n    init (_ placeholder: String = \"\", text: Binding<String>, matches: Binding<[NSTextCheckingResult]>, onCommit: (() -> Void)? = nil) {\n        self.placeholder = placeholder\n        self.onCommit = onCommit\n        _matches = matches\n        _text = text\n        _showingPlaceholder = State<Bool>(initialValue: self.text.isEmpty)\n    }\n\n    var body: some View {\n        MatchesTextViewWrapper(\n            text: internalText,\n            calculatedHeight: $dynamicHeight,\n            matches: matches,\n            onDone: onCommit\n        )\n        .frame(minHeight: dynamicHeight, maxHeight: dynamicHeight)\n        .background(placeholderView, alignment: .topLeading)\n    }\n\n    var placeholderView: some View {\n        Group {\n            if showingPlaceholder {\n                VStack {\n                    Text(placeholder)\n                        .foregroundColor(.secondary)\n                }\n            }\n        }\n    }\n\n}\n\n#if DEBUG\nstruct MatchesTextView_Previews: PreviewProvider {\n    static var test = \"^(\\\\d+)\\\\.(\\\\d{2}) (\\\\d+)\\\\.(\\\\d{2}) (\\\\d+)\\\\.(\\\\d{2}) (\\\\d+)\\\\.(\\\\d{2})\"\n    static var testBinding = Binding<String>(get: { test }, set: { test = $0 })\n    static var matches = [NSTextCheckingResult]()\n    static var matchesBinding = Binding<[NSTextCheckingResult]>(get: { matches }, set: { matches = $0 })\n\n    static var previews: some View {\n        VStack(alignment: .leading) {\n            Text(\"Description:\")\n            MatchesTextView(\"Enter some text here\",\n                          text: testBinding,\n                          matches: matchesBinding) {\n                print(\"Final text: \\(test)\")\n            }\n                .overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.black))\n            Spacer()\n        }\n        .padding()\n    }\n}\n#endif\n"
  },
  {
    "path": "RegEx+/Views/RegExTextView/RegExSyntaxHighlighter.swift",
    "content": "//\n//  RegExSyntaxHighlighter.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/2.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\nimport _RegexParser\n\nenum RegExTextHighlightingMode: Equatable {\n    case plainText\n    case regularExpression(NSRegularExpression.Options)\n\n    var signature: Int {\n        switch self {\n        case .plainText:\n            return 0\n        case .regularExpression(let options):\n            return Int(truncatingIfNeeded: options.rawValue) ^ 0x51A9\n        }\n    }\n}\n\nfileprivate extension NSMutableAttributedString {\n\n    func applyAttributes(_ attributes: [NSAttributedString.Key: Any], to range: Range<String.Index>) {\n        let nsRange = NSRange(range, in: string)\n        addAttributes(attributes, range: nsRange)\n    }\n\n}\n\nfinal class RegExSyntaxHighlighter: NSObject, NSTextStorageDelegate {\n\n    weak var textStorage: NSTextStorage?\n    var highlightingMode: RegExTextHighlightingMode = .regularExpression([])\n\n    private var lastHighlightSignature: Int?\n\n    func highlightRegularExpression(force: Bool = false) {\n        guard let textStorage else {\n            return\n        }\n\n        let signature = highlightSignature(for: textStorage.string)\n        if !force, signature == lastHighlightSignature {\n            return\n        }\n\n        let string = textStorage.string\n        let attributed = NSMutableAttributedString(attributedString: textStorage)\n        let fullRange = NSRange(location: 0, length: attributed.length)\n\n        attributed.removeAttribute(.foregroundColor, range: fullRange)\n        attributed.removeAttribute(.underlineStyle, range: fullRange)\n        attributed.removeAttribute(.underlineColor, range: fullRange)\n        attributed.addAttribute(.foregroundColor, value: UIColor.label, range: fullRange)\n\n        semanticTokens(for: string).sorted(by: tokenSort).forEach { token in\n            attributed.applyAttributes(token.attributes, to: token.range)\n        }\n\n        textStorage.setAttributedString(attributed)\n        lastHighlightSignature = signature\n    }\n\n    func textStorage(\n        _ textStorage: NSTextStorage,\n        didProcessEditing editedMask: NSTextStorage.EditActions,\n        range editedRange: NSRange,\n        changeInLength delta: Int\n    ) {\n        self.textStorage = textStorage\n        highlightRegularExpression()\n    }\n\n}\n\nprivate extension RegExSyntaxHighlighter {\n\n    struct HighlightToken {\n        let range: Range<String.Index>\n        let attributes: [NSAttributedString.Key: Any]\n        let priority: Int\n    }\n\n    struct TokenStyle {\n        let color: UIColor\n        let priority: Int\n    }\n\n    enum HighlightColor {\n        static let quantifier = UIColor.systemGreen\n        static let quantifierRange = UIColor.systemPurple\n        static let structural = UIColor.systemPink\n        static let characterClass = UIColor.systemTeal\n        static let escape = UIColor.systemOrange\n        static let comment = UIColor.systemGray\n        static let directive = UIColor.systemPurple\n        static let error = UIColor.systemRed\n    }\n\n    enum HighlightStyle {\n        static let comment = TokenStyle(color: HighlightColor.comment, priority: 10)\n        static let structural = TokenStyle(color: HighlightColor.structural, priority: 20)\n        static let delimiter = TokenStyle(color: HighlightColor.structural, priority: 30)\n        static let characterClass = TokenStyle(color: HighlightColor.characterClass, priority: 30)\n        static let quantifier = TokenStyle(color: HighlightColor.quantifier, priority: 40)\n        static let quantifierRange = TokenStyle(color: HighlightColor.quantifierRange, priority: 40)\n        static let escape = TokenStyle(color: HighlightColor.escape, priority: 40)\n        static let directive = TokenStyle(color: HighlightColor.directive, priority: 40)\n    }\n\n    func tokenSort(lhs: HighlightToken, rhs: HighlightToken) -> Bool {\n        if lhs.priority != rhs.priority {\n            return lhs.priority < rhs.priority\n        }\n        if lhs.range.lowerBound != rhs.range.lowerBound {\n            return lhs.range.lowerBound < rhs.range.lowerBound\n        }\n        return lhs.range.upperBound < rhs.range.upperBound\n    }\n\n    func highlightSignature(for text: String) -> Int {\n        var hasher = Hasher()\n        hasher.combine(text)\n        hasher.combine(highlightingMode.signature)\n        return hasher.finalize()\n    }\n\n    func semanticTokens(for source: String) -> [HighlightToken] {\n        guard !source.isEmpty else {\n            return []\n        }\n\n        switch highlightingMode {\n        case .plainText:\n            return []\n        case .regularExpression(let options):\n            guard !options.contains(.ignoreMetacharacters) else {\n                return []\n            }\n\n            let ast = parseWithRecovery(source, syntaxOptions(for: options))\n            var tokens = [HighlightToken]()\n\n            if let globalOptions = ast.globalOptions {\n                globalOptions.options.forEach { option in\n                    addColorToken(for: option.location, in: source, style: HighlightStyle.directive, to: &tokens)\n                }\n            }\n\n            collectTokens(from: ast.root, in: source, into: &tokens)\n\n            ast.diags.diags.forEach { diagnostic in\n                addUnderlineToken(for: diagnostic.location, in: source, color: HighlightColor.error, priority: 100, to: &tokens)\n            }\n\n            return tokens\n        }\n    }\n\n    func syntaxOptions(for options: NSRegularExpression.Options) -> SyntaxOptions {\n        var syntax: SyntaxOptions = .traditional\n        if options.contains(.allowCommentsAndWhitespace) {\n            syntax.formUnion(.extendedSyntax)\n        }\n        return syntax\n    }\n\n    // swiftlint:disable:next cyclomatic_complexity\n    func collectTokens(from node: AST.Node, in source: String, into tokens: inout [HighlightToken]) {\n        switch node {\n        case .alternation(let alternation):\n            collectTokens(from: alternation, in: source, into: &tokens)\n\n        case .concatenation(let concatenation):\n            concatenation.children.forEach { child in\n                collectTokens(from: child, in: source, into: &tokens)\n            }\n\n        case .group(let group):\n            collectTokens(from: group, in: source, into: &tokens)\n\n        case .conditional(let conditional):\n            collectTokens(from: conditional, in: source, into: &tokens)\n\n        case .quantification(let quantification):\n            collectTokens(from: quantification, in: source, into: &tokens)\n\n        case .quote(let quote):\n            addColorToken(for: quote.location, in: source, style: HighlightStyle.escape, to: &tokens)\n\n        case .trivia(let trivia):\n            addColorToken(for: trivia.location, in: source, style: HighlightStyle.comment, to: &tokens)\n\n        case .interpolation(let interpolation):\n            addColorToken(for: interpolation.location, in: source, style: HighlightStyle.directive, to: &tokens)\n\n        case .atom(let atom):\n            collectTokens(from: atom, in: source, into: &tokens)\n\n        case .customCharacterClass(let characterClass):\n            collectTokens(from: characterClass, in: source, into: &tokens)\n\n        case .absentFunction(let absentFunction):\n            addColorToken(for: absentFunction.start, in: source, style: HighlightStyle.delimiter, to: &tokens)\n            collectTokens(from: absentFunction, in: source, into: &tokens)\n\n        case .empty:\n            break\n        }\n    }\n\n    func collectTokens(from alternation: AST.Alternation, in source: String, into tokens: inout [HighlightToken]) {\n        alternation.pipes.forEach { pipe in\n            addColorToken(for: pipe, in: source, style: HighlightStyle.structural, to: &tokens)\n        }\n        alternation.children.forEach { child in\n            collectTokens(from: child, in: source, into: &tokens)\n        }\n    }\n\n    func collectTokens(from group: AST.Group, in source: String, into tokens: inout [HighlightToken]) {\n        addDelimitedToken(parent: group.location, child: group.child.location, in: source, style: HighlightStyle.delimiter, to: &tokens)\n        collectTokens(from: group.child, in: source, into: &tokens)\n    }\n\n    func collectTokens(from conditional: AST.Conditional, in source: String, into tokens: inout [HighlightToken]) {\n        addColorToken(for: conditional.location.start ..< conditional.condition.location.end, in: source, style: HighlightStyle.delimiter, to: &tokens)\n        if let pipe = conditional.pipe {\n            addColorToken(for: pipe, in: source, style: HighlightStyle.structural, to: &tokens)\n        }\n        addColorToken(for: conditional.falseBranch.location.end ..< conditional.location.end, in: source, style: HighlightStyle.delimiter, to: &tokens)\n        collectTokens(from: conditional.trueBranch, in: source, into: &tokens)\n        collectTokens(from: conditional.falseBranch, in: source, into: &tokens)\n    }\n\n    func collectTokens(from quantification: AST.Quantification, in source: String, into tokens: inout [HighlightToken]) {\n        collectTokens(from: quantification.child, in: source, into: &tokens)\n        addColorToken(for: quantification.amount.location, in: source, style: style(for: quantification.amount.value), to: &tokens)\n        addColorToken(for: quantification.kind.location, in: source, style: HighlightStyle.quantifier, to: &tokens)\n    }\n\n    func collectTokens(from atom: AST.Atom, in source: String, into tokens: inout [HighlightToken]) {\n        switch atom.kind {\n        case .dot:\n            addColorToken(for: atom.location, in: source, style: HighlightStyle.quantifier, to: &tokens)\n\n        case .caretAnchor, .dollarAnchor:\n            addColorToken(for: atom.location, in: source, style: HighlightStyle.characterClass, to: &tokens)\n\n        case .char:\n            if let range = sourceRange(for: atom.location, in: source), source[range].hasPrefix(\"\\\\\") {\n                tokens.append(\n                    HighlightToken(\n                        range: range,\n                        attributes: [.foregroundColor: HighlightStyle.escape.color],\n                        priority: HighlightStyle.escape.priority\n                    )\n                )\n            }\n\n        case .scalar, .scalarSequence, .property, .escaped,\n             .keyboardControl, .keyboardMeta, .keyboardMetaControl,\n             .namedCharacter, .backreference, .subpattern:\n            addColorToken(for: atom.location, in: source, style: HighlightStyle.escape, to: &tokens)\n\n        case .callout, .backtrackingDirective, .changeMatchingOptions:\n            addColorToken(for: atom.location, in: source, style: HighlightStyle.directive, to: &tokens)\n\n        case .invalid:\n            break\n        }\n    }\n\n    func collectTokens(from characterClass: AST.CustomCharacterClass, in source: String, into tokens: inout [HighlightToken]) {\n        addColorToken(for: characterClass.start.location, in: source, style: HighlightStyle.characterClass, to: &tokens)\n\n        if let closingRange = sourceRange(for: lastChildEnd(in: characterClass.members, defaultingTo: characterClass.start.location.end) ..< characterClass.location.end, in: source) {\n            tokens.append(\n                HighlightToken(\n                    range: closingRange,\n                    attributes: [.foregroundColor: HighlightStyle.characterClass.color],\n                    priority: HighlightStyle.characterClass.priority\n                )\n            )\n        }\n\n        characterClass.members.forEach { member in\n            collectTokens(from: member, in: source, into: &tokens)\n        }\n    }\n\n    func collectTokens(from absentFunction: AST.AbsentFunction, in source: String, into tokens: inout [HighlightToken]) {\n        let closingStart: String.Index\n\n        switch absentFunction.kind {\n        case .repeater(let node), .stopper(let node):\n            collectTokens(from: node, in: source, into: &tokens)\n            closingStart = node.location.end\n\n        case .expression(let absentee, let pipe, let expression):\n            collectTokens(from: absentee, in: source, into: &tokens)\n            addColorToken(for: pipe, in: source, style: HighlightStyle.structural, to: &tokens)\n            collectTokens(from: expression, in: source, into: &tokens)\n            closingStart = expression.location.end\n\n        case .clearer:\n            closingStart = absentFunction.start.end\n        }\n\n        addColorToken(for: closingStart ..< absentFunction.location.end, in: source, style: HighlightStyle.delimiter, to: &tokens)\n    }\n\n    func collectTokens(from member: AST.CustomCharacterClass.Member, in source: String, into tokens: inout [HighlightToken]) {\n        switch member {\n        case .custom(let characterClass):\n            collectTokens(from: characterClass, in: source, into: &tokens)\n\n        case .range(let range):\n            collectTokens(from: range.lhs, in: source, into: &tokens)\n            collectTokens(from: range.rhs, in: source, into: &tokens)\n            addColorToken(for: range.dashLoc, in: source, style: HighlightStyle.characterClass, to: &tokens)\n            range.trivia.forEach { trivia in\n                addColorToken(for: trivia.location, in: source, style: HighlightStyle.comment, to: &tokens)\n            }\n\n        case .atom(let atom):\n            collectTokens(from: atom, in: source, into: &tokens)\n\n        case .quote(let quote):\n            addColorToken(for: quote.location, in: source, style: HighlightStyle.escape, to: &tokens)\n\n        case .trivia(let trivia):\n            addColorToken(for: trivia.location, in: source, style: HighlightStyle.comment, to: &tokens)\n\n        case .setOperation(let lhs, let operation, let rhs):\n            lhs.forEach { collectTokens(from: $0, in: source, into: &tokens) }\n            addColorToken(for: operation.location, in: source, style: HighlightStyle.characterClass, to: &tokens)\n            rhs.forEach { collectTokens(from: $0, in: source, into: &tokens) }\n        }\n    }\n\n    func addDelimitedToken(\n        parent: SourceLocation,\n        child: SourceLocation,\n        in source: String,\n        style: TokenStyle,\n        to tokens: inout [HighlightToken]\n    ) {\n        addColorToken(for: parent.start ..< child.start, in: source, style: style, to: &tokens)\n        addColorToken(for: child.end ..< parent.end, in: source, style: style, to: &tokens)\n    }\n\n    func addColorToken(\n        for location: SourceLocation,\n        in source: String,\n        style: TokenStyle,\n        to tokens: inout [HighlightToken]\n    ) {\n        addColorToken(for: location.range, in: source, style: style, to: &tokens)\n    }\n\n    func addColorToken(\n        for range: Range<String.Index>,\n        in source: String,\n        style: TokenStyle,\n        to tokens: inout [HighlightToken]\n    ) {\n        guard let range = sourceRange(for: range, in: source) else {\n            return\n        }\n\n        tokens.append(\n            HighlightToken(\n                range: range,\n                attributes: [.foregroundColor: style.color],\n                priority: style.priority\n            )\n        )\n    }\n\n    func addUnderlineToken(\n        for location: SourceLocation,\n        in source: String,\n        color: UIColor,\n        priority: Int,\n        to tokens: inout [HighlightToken]\n    ) {\n        guard let range = sourceRange(for: location, in: source) else {\n            return\n        }\n\n        tokens.append(\n            HighlightToken(\n                range: range,\n                attributes: [\n                    .underlineStyle: NSUnderlineStyle.single.rawValue,\n                    .underlineColor: color\n                ],\n                priority: priority\n            )\n        )\n    }\n\n    func sourceRange(for location: SourceLocation, in source: String) -> Range<String.Index>? {\n        sourceRange(for: location.range, in: source)\n    }\n\n    func sourceRange(for range: Range<String.Index>, in source: String) -> Range<String.Index>? {\n        guard range.lowerBound >= source.startIndex,\n              range.upperBound <= source.endIndex,\n              range.lowerBound <= range.upperBound else {\n            return nil\n        }\n\n        return range\n    }\n\n    func lastChildEnd(in members: [AST.CustomCharacterClass.Member], defaultingTo fallback: String.Index) -> String.Index {\n        members.last?.location.end ?? fallback\n    }\n\n    func style(for amount: AST.Quantification.Amount) -> TokenStyle {\n        switch amount {\n        case .exactly, .nOrMore, .upToN, .range:\n            return HighlightStyle.quantifierRange\n        case .zeroOrMore, .oneOrMore, .zeroOrOne:\n            return HighlightStyle.quantifier\n        }\n    }\n\n}\n"
  },
  {
    "path": "RegEx+/Views/RegExTextView/RegExTextView.swift",
    "content": "//\n//  RegExSyntaxView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/4/23.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\nimport Combine\nimport UIKit\n\n\n// Credit to: Asperi https://stackoverflow.com/users/12299030/asperi\n// https://stackoverflow.com/a/58639072/1209135\nstruct UITextViewWrapper: UIViewRepresentable {\n    typealias UIViewType = UITextView\n\n    @Binding var text: String\n    @Binding var calculatedHeight: CGFloat\n    var onDone: (() -> Void)?\n    @Binding var coordinator: Coordinator?\n    var showShortcutBar: Bool\n    var highlightingMode: RegExTextHighlightingMode\n    \n    private let syntaxHighlighter = RegExSyntaxHighlighter()\n\n    func makeUIView(context: UIViewRepresentableContext<UITextViewWrapper>) -> UITextView {\n        let tv = UITextView()\n        tv.delegate = context.coordinator\n        syntaxHighlighter.highlightingMode = highlightingMode\n        tv.textStorage.delegate = syntaxHighlighter\n\n        let font = UIFont.preferredFont(forTextStyle: .body)\n\n        tv.isEditable = true\n        tv.font = font.withSize(font.pointSize + 2)\n        tv.isSelectable = true\n        tv.autocorrectionType = .no\n        tv.spellCheckingType = .no\n        tv.keyboardType = .emailAddress\n        tv.isUserInteractionEnabled = true\n        tv.isScrollEnabled = false\n        tv.backgroundColor = UIColor.clear\n        \n        tv.textContainerInset = .zero\n        tv.textContainer.lineFragmentPadding = 0\n        if nil != onDone {\n            tv.returnKeyType = .done\n        }\n\n        context.coordinator.textView = tv\n        coordinator = context.coordinator\n\n#if !targetEnvironment(macCatalyst)\n        // Set up input accessory view for shortcut bar on iOS\n        if showShortcutBar {\n            let accessoryView = ShortcutKeysAccessoryView()\n            accessoryView.textView = tv\n            accessoryView.coordinator = context.coordinator\n            tv.inputAccessoryView = accessoryView\n        }\n#endif\n\n        return tv\n    }\n\n    func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<UITextViewWrapper>) {\n        uiView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)\n        uiView.textContainer.lineBreakMode = .byCharWrapping\n        if uiView.text != text {\n            uiView.text = text\n        }\n\n        syntaxHighlighter.textStorage = uiView.textStorage\n        syntaxHighlighter.highlightingMode = highlightingMode\n        syntaxHighlighter.highlightRegularExpression(force: true)\n        \n        // Calculate height synchronously since we're already on the main thread\n        UITextViewWrapper.recalculateHeight(view: uiView, result: $calculatedHeight)\n    }\n\n    fileprivate static func recalculateHeight(view: UIView, result: Binding<CGFloat>) {\n        let newSize = view.sizeThatFits(CGSize(width: view.frame.size.width, height: CGFloat.greatestFiniteMagnitude))\n        if result.wrappedValue != newSize.height {\n            result.wrappedValue = newSize.height\n        }\n    }\n\n    func makeCoordinator() -> Coordinator {\n        return Coordinator(text: $text, height: $calculatedHeight, onDone: onDone)\n    }\n\n    final class Coordinator: NSObject, UITextViewDelegate {\n        var text: Binding<String>\n        var calculatedHeight: Binding<CGFloat>\n        var onDone: (() -> Void)?\n        weak var textView: UITextView?\n\n        init(text: Binding<String>, height: Binding<CGFloat>, onDone: (() -> Void)? = nil) {\n            self.text = text\n            self.calculatedHeight = height\n            self.onDone = onDone\n            super.init()\n        }\n\n        func textViewDidChange(_ uiView: UITextView) {\n            // Only update if text actually changed\n            if text.wrappedValue != uiView.text {\n                text.wrappedValue = uiView.text\n                UITextViewWrapper.recalculateHeight(view: uiView, result: calculatedHeight)\n            }\n        }\n\n        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {\n            if let onDone = self.onDone, text == \"\\n\" {\n                textView.resignFirstResponder()\n                onDone()\n                return false\n            }\n            return true\n        }\n    }\n\n}\n\nstruct RegExTextView: View, Equatable {\n\n    private var placeholder: String\n    private var onCommit: (() -> Void)?\n    private var showShortcutBar: Bool\n    private var highlightingMode: RegExTextHighlightingMode\n\n    @Binding private var text: String\n    private var internalText: Binding<String> {\n        Binding<String>(get: { self.text }) {\n            self.text = $0\n            self.showingPlaceholder = $0.isEmpty\n        }\n    }\n    \n    @State private var dynamicHeight: CGFloat = 20\n    @State private var showingPlaceholder = false\n    @State private var coordinator: UITextViewWrapper.Coordinator?\n\n    init (\n        _ placeholder: String = \"\",\n        text: Binding<String>,\n        onCommit: (() -> Void)? = nil,\n        showShortcutBar: Bool = false,\n        highlightingMode: RegExTextHighlightingMode = .regularExpression([])\n    ) {\n        self.placeholder = placeholder\n        self.onCommit = onCommit\n        self._text = text\n        self.showShortcutBar = showShortcutBar\n        self.highlightingMode = highlightingMode\n        self._showingPlaceholder = State<Bool>(initialValue: text.wrappedValue.isEmpty)\n    }\n\n    var body: some View {\n        UITextViewWrapper(\n            text: internalText,\n            calculatedHeight: $dynamicHeight,\n            onDone: onCommit,\n            coordinator: $coordinator,\n            showShortcutBar: showShortcutBar,\n            highlightingMode: highlightingMode\n        )\n        .frame(minHeight: dynamicHeight, maxHeight: dynamicHeight)\n        .background(placeholderView, alignment: .topLeading)\n    }\n\n    var placeholderView: some View {\n        Group {\n            if showingPlaceholder {\n                VStack {\n                    Text(placeholder)\n                        .foregroundColor(.secondary)\n                }\n            }\n        }\n    }\n\n    static func == (lhs: RegExTextView, rhs: RegExTextView) -> Bool {\n        lhs.text == rhs.text && lhs.highlightingMode == rhs.highlightingMode\n    }\n\n}\n\n#if DEBUG\nstruct RegExTextView_Previews: PreviewProvider {\n    static var test = #\"^(\\d+)\\.(\\d{2}) (\\d+)\\.(\\d{2}) (\\d+)\\.(\\d{2}) (\\d+)\\.(\\d{2})\"#\n    static var testBinding = Binding<String>(get: { test }, set: { test = $0 })\n\n    static var previews: some View {\n        Group {\n            VStack(alignment: .leading) {\n                RegExTextView(\"Enter some text here\", text: testBinding, onCommit: {\n                    print(\"Final text: \\(test)\")\n                }, showShortcutBar: true)\n                .overlay(\n                    RoundedRectangle(cornerRadius: 4).stroke(Color.black)\n                )\n            }\n            VStack(alignment: .leading) {\n                RegExTextView(\"Enter some text here\", text: testBinding, onCommit: {\n                    print(\"Final text: \\(test)\")\n                }, showShortcutBar: false)\n                .overlay(\n                    RoundedRectangle(cornerRadius: 4).stroke(Color.black)\n                )\n            }\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "RegEx+/Views/RegExTextView/ShortcutKeys.swift",
    "content": "//\n//  ShortcutKeys.swift\n//  RegEx+\n//\n//  Created by Lex on 8/10/25.\n//  Copyright © 2025 Lex.sh. All rights reserved.\n//\n\nimport UIKit\n\nextension UIFont {\n    func withWeight(_ weight: UIFont.Weight) -> UIFont {\n        let descriptor = fontDescriptor.addingAttributes([\n            .traits: [UIFontDescriptor.TraitKey.weight: weight]\n        ])\n        return UIFont(descriptor: descriptor, size: pointSize)\n    }\n}\n\nenum ShortcutKey: String, CaseIterable {\n    case leftArrow = \"←\"\n    case rightArrow = \"→\"\n    case asterisk = \"*\"\n    case question = \"?\"\n    case openBracket = \"[\"\n    case closeBracket = \"]\"\n    case openParen = \"(\"\n    case closeParen = \")\"\n    case backslash = \"\\\\\"\n    case dollar = \"$\"\n    case caret = \"^\"\n    case dot = \".\"\n    case plus = \"+\"\n    case minus = \"-\"\n    case pipe = \"|\"\n    case openBrace = \"{\"\n    case closeBrace = \"}\"\n\n    var displayText: String {\n        return self.rawValue\n    }\n\n    var accessibilityLabel: String {\n        switch self {\n        case .asterisk: return \"Asterisk\"\n        case .question: return \"Question mark\"\n        case .openBracket: return \"Open bracket\"\n        case .closeBracket: return \"Close bracket\"\n        case .openParen: return \"Open parenthesis\"\n        case .closeParen: return \"Close parenthesis\"\n        case .backslash: return \"Backslash\"\n        case .dollar: return \"Dollar sign\"\n        case .caret: return \"Caret\"\n        case .dot: return \"Dot\"\n        case .plus: return \"Plus\"\n        case .minus: return \"Minus\"\n        case .pipe: return \"Pipe\"\n        case .openBrace: return \"Open brace\"\n        case .closeBrace: return \"Close brace\"\n        case .leftArrow: return \"Left arrow\"\n        case .rightArrow: return \"Right arrow\"\n        }\n    }\n\n    var isCharKey: Bool {\n        switch self {\n        case .leftArrow, .rightArrow: false\n        default: true\n        }\n    }\n}\n\nprivate let keyWidth: CGFloat = 35\nprivate let keyHeight: CGFloat = 40\nprivate let keyHorizontalMargin: CGFloat = 6\nprivate let keyVerticalSpacing: CGFloat = 8\n\nclass ShortcutKeysUIKitView: UIView {\n    private let onKeyTapped: (ShortcutKey) -> Void\n    private let scrollView = UIScrollView()\n    private let contentStackView = UIStackView()\n    \n    init(onKeyTapped: @escaping (ShortcutKey) -> Void) {\n        self.onKeyTapped = onKeyTapped\n        super.init(frame: .zero)\n        setupView()\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    private func setupView() {\n        backgroundColor = .systemBackground\n        \n        let separatorTop = UIView()\n        separatorTop.backgroundColor = .separator\n        separatorTop.translatesAutoresizingMaskIntoConstraints = false\n        \n        let mainStackView = UIStackView()\n        mainStackView.axis = .horizontal\n        mainStackView.alignment = .center\n        mainStackView.spacing = keyHorizontalMargin\n        mainStackView.translatesAutoresizingMaskIntoConstraints = false\n        \n        let arrowKeysStackView = UIStackView()\n        arrowKeysStackView.axis = .horizontal\n        arrowKeysStackView.spacing = keyHorizontalMargin\n        arrowKeysStackView.translatesAutoresizingMaskIntoConstraints = false\n        \n        let arrowKeys = ShortcutKey.allCases.filter { !$0.isCharKey }\n        for key in arrowKeys {\n            let button = createKeyButton(for: key, isBold: true)\n            arrowKeysStackView.addArrangedSubview(button)\n        }\n        \n        let separatorVertical = UIView()\n        separatorVertical.backgroundColor = .separator\n        separatorVertical.translatesAutoresizingMaskIntoConstraints = false\n        \n        scrollView.showsHorizontalScrollIndicator = false\n        scrollView.alwaysBounceVertical = false\n        scrollView.translatesAutoresizingMaskIntoConstraints = false\n        \n        contentStackView.axis = .horizontal\n        contentStackView.spacing = keyHorizontalMargin\n        contentStackView.translatesAutoresizingMaskIntoConstraints = false\n\n        let charKeys = ShortcutKey.allCases.filter(\\.isCharKey)\n        for key in charKeys {\n            let button = createKeyButton(for: key, isBold: false)\n            contentStackView.addArrangedSubview(button)\n        }\n        \n        scrollView.addSubview(contentStackView)\n        \n        mainStackView.addArrangedSubview(arrowKeysStackView)\n        mainStackView.addArrangedSubview(separatorVertical)\n        mainStackView.addArrangedSubview(scrollView)\n        \n        addSubview(separatorTop)\n        addSubview(mainStackView)\n        \n        NSLayoutConstraint.activate([\n            separatorTop.topAnchor.constraint(equalTo: topAnchor),\n            separatorTop.leadingAnchor.constraint(equalTo: leadingAnchor),\n            separatorTop.trailingAnchor.constraint(equalTo: trailingAnchor),\n            separatorTop.heightAnchor.constraint(equalToConstant: 0.5),\n            \n            mainStackView.topAnchor.constraint(equalTo: separatorTop.bottomAnchor, constant: keyVerticalSpacing),\n            mainStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: keyHorizontalMargin),\n            mainStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -keyHorizontalMargin),\n            mainStackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -keyVerticalSpacing),\n            \n            separatorVertical.widthAnchor.constraint(equalToConstant: 1),\n            separatorVertical.heightAnchor.constraint(equalToConstant: keyHeight),\n            \n            contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor),\n            contentStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),\n            contentStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),\n            contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),\n            contentStackView.heightAnchor.constraint(equalTo: scrollView.heightAnchor)\n        ])\n    }\n    \n    private func createKeyButton(for key: ShortcutKey, isBold: Bool) -> UIButton {\n        let button = UIButton(type: .system)\n        button.setTitle(key.displayText, for: .normal)\n        button.titleLabel?.font = isBold ? UIFont.preferredFont(forTextStyle: .title2).withWeight(.bold) : UIFont.preferredFont(forTextStyle: .title2)\n        button.setTitleColor(.label, for: .normal)\n        button.backgroundColor = .secondarySystemFill\n        button.layer.cornerRadius = 8\n        button.translatesAutoresizingMaskIntoConstraints = false\n        \n        button.accessibilityLabel = key.accessibilityLabel\n        if key.isCharKey {\n            button.accessibilityHint = \"Insert \\(key.accessibilityLabel.lowercased()) into text\"\n        } else {\n            button.accessibilityHint = key.accessibilityLabel\n        }\n        \n        button.addTarget(self, action: #selector(keyTapped(_:)), for: .touchUpInside)\n        button.tag = ShortcutKey.allCases.firstIndex(of: key) ?? 0\n        \n        NSLayoutConstraint.activate([\n            button.widthAnchor.constraint(equalToConstant: keyWidth),\n            button.heightAnchor.constraint(equalToConstant: keyHeight)\n        ])\n        \n        return button\n    }\n    \n    @objc private func keyTapped(_ sender: UIButton) {\n        let key = ShortcutKey.allCases[sender.tag]\n        onKeyTapped(key)\n    }\n}\n\nclass ShortcutKeysAccessoryView: UIView {\n    weak var textView: UITextView?\n    weak var coordinator: UITextViewWrapper.Coordinator?\n    \n    private var shortcutKeysView: ShortcutKeysUIKitView?\n\n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        setupView()\n    }\n\n    required init?(coder: NSCoder) {\n        super.init(coder: coder)\n        setupView()\n    }\n\n    private func setupView() {\n        let shortcutKeysView = ShortcutKeysUIKitView { [weak self] key in\n            self?.handleKeyTapped(key)\n        }\n        \n        shortcutKeysView.translatesAutoresizingMaskIntoConstraints = false\n        \n        addSubview(shortcutKeysView)\n        self.shortcutKeysView = shortcutKeysView\n\n        translatesAutoresizingMaskIntoConstraints = false\n\n        NSLayoutConstraint.activate([\n            shortcutKeysView.topAnchor.constraint(equalTo: topAnchor),\n            shortcutKeysView.leadingAnchor.constraint(equalTo: leadingAnchor),\n            shortcutKeysView.trailingAnchor.constraint(equalTo: trailingAnchor),\n            shortcutKeysView.bottomAnchor.constraint(equalTo: bottomAnchor),\n            heightAnchor.constraint(equalToConstant: keyHeight + keyVerticalSpacing * 2 + 1)\n        ])\n    }\n\n    private func handleKeyTapped(_ key: ShortcutKey) {\n        guard let textView = textView else { return }\n\n        let selectedRange = textView.selectedRange\n        \n        // Handle cursor movement keys\n        if key == .leftArrow {\n            let newPosition = max(0, selectedRange.location - 1)\n            textView.selectedRange = NSRange(location: newPosition, length: 0)\n            return\n        } else if key == .rightArrow {\n            let textLength = textView.text?.count ?? 0\n            let newPosition = min(textLength, selectedRange.location + 1)\n            textView.selectedRange = NSRange(location: newPosition, length: 0)\n            return\n        }\n        \n        // Handle text insertion keys\n        let currentText = textView.text ?? \"\"\n        let newText = (currentText as NSString).replacingCharacters(in: selectedRange, with: key.rawValue)\n\n        textView.text = newText\n\n        let newCursorPosition = selectedRange.location + key.rawValue.count\n        textView.selectedRange = NSRange(location: newCursorPosition, length: 0)\n\n        // Update the binding through coordinator\n        if let coordinator = coordinator {\n            coordinator.text.wrappedValue = newText\n        }\n\n        // Trigger syntax highlighting if available\n        if let textStorage = textView.textStorage.delegate as? RegExSyntaxHighlighter {\n            textStorage.textStorage = textView.textStorage\n            textStorage.highlightRegularExpression()\n        }\n\n        // Notify delegate of text change to trigger height recalculation\n        if let delegate = textView.delegate {\n            delegate.textViewDidChange?(textView)\n        }\n    }\n}\n"
  },
  {
    "path": "RegEx+/Views/RegExTextView/String+NSRange.swift",
    "content": "//\n//  String+NSRange.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/2.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport Foundation\n\n\nextension String {\n\n    func nsRange(from range: Range<String.Index>) -> NSRange {\n        let startPos = self.distance(from: self.startIndex, to: range.lowerBound)\n        let endPos = self.distance(from: self.startIndex, to: range.upperBound)\n        return NSRange(location: startPos, length: endPos - startPos)\n    }\n\n}\n\nextension String {\n\n    func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] {\n        var ranges: [Range<Index>] = []\n        while let range = range(of: substring,\n                                options: options,\n                                range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale) {\n            ranges.append(range)\n        }\n        return ranges\n    }\n\n}\n"
  },
  {
    "path": "RegEx+/Views/SafariView.swift",
    "content": "//\n//  SafariView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/5/5.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\nimport SafariServices\n\n\nstruct SafariView: UIViewControllerRepresentable {\n    typealias UIViewControllerType = SFSafariViewController\n\n    var url: URL\n\n    func makeUIViewController(context: UIViewControllerRepresentableContext<SafariView>) -> SFSafariViewController {\n        return SFSafariViewController(url: url)\n    }\n\n    func updateUIViewController(_ safariViewController: SFSafariViewController, context: UIViewControllerRepresentableContext<SafariView>) {\n    }\n}\n\n#if DEBUG\nstruct SafariView_Previews: PreviewProvider {\n    static var previews: some View {\n        SafariView(url: URL(string: \"https://www.apple.com\")!)\n    }\n}\n#endif\n"
  },
  {
    "path": "RegEx+/Views/SearchView.swift",
    "content": "//\n//  SearchView.swift\n//  RegEx+\n//\n//  Created by Lex on 2020/10/4.\n//  Copyright © 2020 Lex.sh. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct SearchView: View {\n    @Binding var text: String\n\n    @State private var isEditing = false\n\n    private var cornerRadius: CGFloat {\n        #if targetEnvironment(macCatalyst)\n            5\n        #else\n            18\n        #endif\n    }\n\n    var body: some View {\n        TextField(\"Search...\", text: $text)\n            .padding(.horizontal, 32)\n            .padding(.vertical, 5)\n            .background(Color(.systemGray6))\n            .cornerRadius(cornerRadius)\n            .overlay(\n                HStack {\n                    Image(systemName: \"magnifyingglass\")\n                        .foregroundColor(.gray)\n                        .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)\n                        .padding(.leading, 10)\n\n                    if isEditing && !text.isEmpty {\n                        Button(action: {\n                            self.text = \"\"\n                        }) {\n                            Image(systemName: \"multiply.circle.fill\")\n                                .foregroundColor(.gray)\n                                .padding(.trailing, 8)\n                        }\n                        .buttonStyle(.borderless)\n                    }\n                }\n            )\n            .disableAutocorrection(true)\n            .onTapGesture {\n                self.isEditing = true\n            }\n    }\n}\n\nstruct SearchView_Previews: PreviewProvider {\n    static var previews: some View {\n        VStack {\n            SearchView(text: .constant(\"\"))\n                .preferredColorScheme(.dark)\n        }\n        .padding()\n        .background(Color.white)\n    }\n}\n"
  },
  {
    "path": "RegEx+/de.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem BELL, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht dem Anfang der Eingabe. Unterscheidet sich von ^ dadurch, dass \\A nicht nach einem Zeilenumbruch innerhalb der Eingabe entspricht.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht, wenn die aktuelle Position eine Wortgrenze ist. Grenzen treten bei Übergängen zwischen Wort- (\\w) und Nicht-Wort-Zeichen (\\W) auf, wobei kombinierende Zeichen ignoriert werden. Für bessere Wortgrenzen siehe useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht, wenn die aktuelle Position keine Wortgrenze ist.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Control-X-Zeichen</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht jedem Zeichen der Unicode-Kategorie Nd (Number, Decimal Digit)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht jedem Zeichen, das keine Dezimalziffer ist</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem ESCAPE, \\u001B</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Beendet eine \\Q ... \\E-Quotierung</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem FORM FEED, \\u000C</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht, wenn die aktuelle Position am Ende der vorherigen Übereinstimmung ist</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem LINE FEED, \\u000A</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht dem benannten Zeichen</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht jedem Zeichen mit der angegebenen Unicode-Eigenschaft</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht jedem Zeichen ohne die angegebene Unicode-Eigenschaft</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Quotiert alle folgenden Zeichen bis \\E</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem CARRIAGE RETURN, \\u000D</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Leerzeichen. Leerzeichen sind definiert als [\\t\\n\\f\\r\\p{Z}]</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Nicht-Leerzeichen</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem HORIZONTAL TABULATION, \\u0009</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht dem Zeichen mit dem Hexadezimalwert hhhh</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht dem Zeichen mit dem Hexadezimalwert hhhhhhhh. Genau acht Hexadezimalziffern müssen angegeben werden, obwohl der größte Unicode-Codepunkt \\U0010ffff ist</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Wortzeichen. Wortzeichen sind [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}]</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Nicht-Wortzeichen</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht dem Zeichen mit dem Hexadezimalwert hhhh. Ein bis sechs Hexadezimalziffern können angegeben werden</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht dem Zeichen mit dem zweistelligen Hexadezimalwert hh</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Graphem-Cluster</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht, wenn die aktuelle Position am Ende der Eingabe ist, aber vor dem abschließenden Zeilenterminator, falls einer existiert</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht, wenn die aktuelle Position am Ende der Eingabe ist</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Rückverweis. Entspricht dem, was die n-te Erfassungsgruppe erfasst hat. n muss eine Zahl ≥ 1 und ≤ der Gesamtzahl der Erfassungsgruppen im Muster sein</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem Oktalzeichen. ooo sind ein bis drei Oktalziffern. 0377 ist das größte erlaubte Oktalzeichen. Die führende Null ist erforderlich; sie unterscheidet Oktalkonstanten von Rückverweisen</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem beliebigen Zeichen aus dem Muster</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht einem beliebigen Zeichen</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht am Anfang einer Zeile</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht am Ende einer Zeile</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Quotiert das folgende Zeichen. Zeichen, die quotiert werden müssen, um als Literale behandelt zu werden, sind * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternative. A|B entspricht entweder A oder B</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht 0 oder mehrmals. Entspricht so oft wie möglich</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht 1 oder mehrmals. Entspricht so oft wie möglich</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht null oder einmal. Bevorzugt einmal</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht genau n-mal</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht mindestens n-mal. Entspricht so oft wie möglich</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht zwischen n und m Mal. Entspricht so oft wie möglich, aber nicht mehr als m-mal</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht 0 oder mehrmals. Entspricht so wenig wie möglich</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht 1 oder mehrmals. Entspricht so wenig wie möglich</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht null oder einmal. Bevorzugt null</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht genau n-mal</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht mindestens n-mal, aber nicht mehr als für eine Gesamtmuster-Übereinstimmung erforderlich</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht zwischen n und m Mal. Entspricht so wenig wie möglich, aber nicht weniger als n-mal</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht 0 oder mehrmals. Entspricht so oft wie möglich beim ersten Auftreten, wiederholt nicht mit weniger, auch wenn die Gesamtübereinstimmung fehlschlägt (Possessive Match)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht 1 oder mehrmals. Possessive Match</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht null oder einmal. Possessive Match</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht genau n-mal</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht mindestens n-mal. Possessive Match</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entspricht zwischen n und m Mal. Possessive Match</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Erfassungsklammern. Der Bereich der Eingabe, der dem geklammerten Teilausdruck entspricht, ist nach der Übereinstimmung verfügbar</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Nicht-erfassende Klammern. Gruppiert das enthaltene Muster, erfasst aber nicht den übereinstimmenden Text. Etwas effizienter als erfassende Klammern</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Atomare Klammern. Die erste Übereinstimmung des geklammerten Teilausdrucks ist die einzige, die versucht wird; wenn sie nicht zu einer Gesamtmuster-Übereinstimmung führt, geht die Suche zu einer Position vor &quot;(?&gt;&quot; zurück</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Freiformatkommentar (?# Kommentar )</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Vorausschau-Zusicherung. Wahr, wenn das geklammerte Muster an der aktuellen Eingabeposition entspricht, aber die Eingabeposition nicht voranschreitet</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negative Vorausschau-Zusicherung. Wahr, wenn das geklammerte Muster an der aktuellen Eingabeposition nicht entspricht. Schreitet die Eingabeposition nicht voran</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Rückblick-Zusicherung. Wahr, wenn das geklammerte Muster dem Text vor der aktuellen Eingabeposition entspricht, wobei das letzte Zeichen der Übereinstimmung das Eingabezeichen unmittelbar vor der aktuellen Position ist. Verändert die Eingabeposition nicht. Die Länge möglicher Zeichenketten, die vom Rückblick-Muster erfasst werden, darf nicht unbegrenzt sein (keine * oder + Operatoren)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negative Rückblick-Zusicherung. Wahr, wenn das geklammerte Muster nicht dem Text vor der aktuellen Eingabeposition entspricht, wobei das letzte Zeichen der Übereinstimmung das Eingabezeichen unmittelbar vor der aktuellen Position wäre. Verändert die Eingabeposition nicht. Die Länge möglicher Zeichenketten, die vom Rückblick-Muster erfasst werden, darf nicht unbegrenzt sein (keine * oder + Operatoren)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Flag-Einstellungen. Wertet den geklammerten Ausdruck mit den angegebenen aktivierten oder -deaktivierten Flags aus. Die Flags sind in Flag-Optionen definiert</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Flag-Einstellungen. Ändert die Flag-Einstellungen. Änderungen gelten für den Teil des Musters nach der Einstellung. Zum Beispiel ändert (?i) zu einer groß-/kleinschreibungsunabhängigen Übereinstimmung. Die Flags sind in Flag-Optionen definiert</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/en.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a BELL, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match at the beginning of the input. Differs from ^ in that \\A will not match after a new line within the input.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match if the current position is a word boundary. Boundaries occur at the transitions between word (\\w) and non-word (\\W) characters, with combining marks ignored. For better word boundaries, see useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match if the current position is not a word boundary.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a control-X character</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match any character with the Unicode General Category of Nd (Number, Decimal Digit.)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match any character that is not a decimal digit.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match an ESCAPE, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Terminates a \\Q ... \\E quoted sequence.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a FORM FEED, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match if the current position is at the end of the previous match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a LINE FEED, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match the named character.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match any character with the specified Unicode Property.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match any character not having the specified Unicode Property.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Quotes all following characters until \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a CARRIAGE RETURN, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a white space character. White space is defined as [\\t\\n\\f\\r\\p{Z}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a non-white space character.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a HORIZONTAL TABULATION, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match the character with the hex value hhhh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match the character with the hex value hhhhhhhh. Exactly eight hex digits must be provided, even though the largest Unicode code point is \\U0010ffff.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a word character. Word characters are [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a non-word character.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match the character with hex value hhhh. From one to six hex digits may be supplied.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match the character with two digit hex value hh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match a Grapheme Cluster.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match if the current position is at the end of input, but before the final line terminator, if one exists.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match if the current position is at the end of input.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Back Reference. Match whatever the nth capturing group matched. n must be a number ≥ 1 and ≤ total number of capture groups in the pattern.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match an Octal character. ooo is from one to three octal digits. 0377 is the largest allowed Octal character. The leading zero is required; it distinguishes Octal constants from back references.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match any one character from the pattern.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match any character.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match at the beginning of a line.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match at the end of a line.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Quotes the following character. Characters that must be quoted to be treated as literals are * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternation. A|B matches either A or B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match 0 or more times. Match as many times as possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match 1 or more times. Match as many times as possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match zero or one times. Prefer one.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match exactly n times.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match at least n times. Match as many times as possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match between n and m times. Match as many times as possible, but not more than m.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match 0 or more times. Match as few times as possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match 1 or more times. Match as few times as possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match zero or one times. Prefer zero.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match exactly n times.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match at least n times, but no more than required for an overall pattern match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match between n and m times. Match as few times as possible, but not less than n.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match 0 or more times. Match as many times as possible when first encountered, do not retry with fewer even if overall match fails (Possessive Match).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match 1 or more times. Possessive match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match zero or one times. Possessive match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match exactly n times.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match at least n times. Possessive Match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Match between n and m times. Possessive Match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Capturing parentheses. Range of input that matched the parenthesized subexpression is available after the match.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Non-capturing parentheses. Groups the included pattern, but does not provide capturing of matching text. Somewhat more efficient than capturing parentheses.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Atomic-match parentheses. First match of the parenthesized subexpression is the only one tried; if it does not lead to an overall pattern match, back up the search for a match to a position before the &quot;(?&gt;&quot;</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Free-format comment (?# comment ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Look-ahead assertion. True if the parenthesized pattern matches at the current input position, but does not advance the input position.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negative look-ahead assertion. True if the parenthesized pattern does not match at the current input position. Does not advance the input position.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Look-behind assertion. True if the parenthesized pattern matches text preceding the current input position, with the last character of the match being the input character just before the current position. Does not alter the input position. The length of possible strings matched by the look-behind pattern must not be unbounded (no * or + operators.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negative Look-behind assertion. True if the parenthesized pattern does not match text preceding the current input position, with the last character of the match being the input character just before the current position. Does not alter the input position. The length of possible strings matched by the look-behind pattern must not be unbounded (no * or + operators.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Flag settings. Evaluate the parenthesized expression with the specified flags enabled or -disabled. The flags are defined in Flag Options.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Flag settings. Change the flag settings. Changes apply to the portion of the pattern following the setting. For example, (?i) changes to a case insensitive match.The flags are defined in Flag Options.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/es.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un BELL, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide al principio de la entrada. Se diferencia de ^ en que \\A no coincidirá después de una nueva línea dentro de la entrada.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide si la posición actual es un límite de palabra. Los límites ocurren en las transiciones entre caracteres de palabra (\\w) y no-palabra (\\W), ignorando las marcas de combinación. Para mejores límites de palabra, consulte useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide si la posición actual no es un límite de palabra.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un carácter control-X</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con cualquier carácter con la Categoría General Unicode de Nd (Number, Decimal Digit.)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con cualquier carácter que no sea un dígito decimal.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un ESCAPE, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Termina una secuencia entrecomillada \\Q ... \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un FORM FEED, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide si la posición actual está al final de la coincidencia anterior.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un LINE FEED, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con el carácter nombrado.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con cualquier carácter con la Propiedad Unicode especificada.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con cualquier carácter que no tenga la Propiedad Unicode especificada.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entrecomilla todos los caracteres siguientes hasta \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un CARRIAGE RETURN, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un carácter de espacio en blanco. El espacio en blanco se define como [\\t\\n\\f\\r\\p{Z}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un carácter que no sea espacio en blanco.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un HORIZONTAL TABULATION, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con el carácter con el valor hexadecimal hhhh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con el carácter con el valor hexadecimal hhhhhhhh. Deben proporcionarse exactamente ocho dígitos hexadecimales, aunque el punto de código Unicode más grande sea \\U0010ffff.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un carácter de palabra. Los caracteres de palabra son [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un carácter que no sea de palabra.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con el carácter con valor hexadecimal hhhh. Se pueden proporcionar de uno a seis dígitos hexadecimales.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con el carácter con valor hexadecimal de dos dígitos hh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un Clúster de Grafemas.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide si la posición actual está al final de la entrada, pero antes del terminador de línea final, si existe uno.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide si la posición actual está al final de la entrada.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Referencia hacia atrás. Coincide con lo que sea que el n-ésimo grupo de captura haya coincidido. n debe ser un número ≥ 1 y ≤ número total de grupos de captura en el patrón.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con un carácter Octal. ooo es de uno a tres dígitos octales. 0377 es el carácter Octal más grande permitido. El cero inicial es requerido; distingue las constantes Octales de las referencias hacia atrás.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con cualquier carácter del patrón.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide con cualquier carácter.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide al principio de una línea.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide al final de una línea.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Entrecomilla el siguiente carácter. Los caracteres que deben entrecomillarse para ser tratados como literales son * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternancia. A|B coincide con A o B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide 0 o más veces. Coincide tantas veces como sea posible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide 1 o más veces. Coincide tantas veces como sea posible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide cero o una vez. Prefiere una.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide exactamente n veces.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide al menos n veces. Coincide tantas veces como sea posible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide entre n y m veces. Coincide tantas veces como sea posible, pero no más de m.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide 0 o más veces. Coincide tan pocas veces como sea posible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide 1 o más veces. Coincide tan pocas veces como sea posible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide cero o una vez. Prefiere cero.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide exactamente n veces.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide al menos n veces, pero no más de lo requerido para una coincidencia general del patrón.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide entre n y m veces. Coincide tan pocas veces como sea posible, pero no menos de n.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide 0 o más veces. Coincide tantas veces como sea posible al encontrarse por primera vez, no reintenta con menos aunque la coincidencia general falle (Coincidencia Posesiva).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide 1 o más veces. Coincidencia posesiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide cero o una vez. Coincidencia posesiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide exactamente n veces.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide al menos n veces. Coincidencia Posesiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Coincide entre n y m veces. Coincidencia Posesiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Paréntesis de captura. El rango de entrada que coincidió con la subexpresión entre paréntesis está disponible después de la coincidencia.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Paréntesis de no captura. Agrupa el patrón incluido, pero no proporciona captura del texto coincidente. Algo más eficiente que los paréntesis de captura.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Paréntesis de coincidencia atómica. La primera coincidencia de la subexpresión entre paréntesis es la única que se intenta; si no lleva a una coincidencia general del patrón, retrocede la búsqueda de una coincidencia a una posición antes del &quot;(?&gt;&quot;</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Comentario de formato libre (?# comentario ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Aserción de búsqueda hacia adelante. Verdadero si el patrón entre paréntesis coincide en la posición de entrada actual, pero no avanza la posición de entrada.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Aserción negativa de búsqueda hacia adelante. Verdadero si el patrón entre paréntesis no coincide en la posición de entrada actual. No avanza la posición de entrada.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Aserción de búsqueda hacia atrás. Verdadero si el patrón entre paréntesis coincide con el texto que precede a la posición de entrada actual, siendo el último carácter de la coincidencia el carácter de entrada justo antes de la posición actual. No altera la posición de entrada. La longitud de las posibles cadenas coincidentes del patrón de búsqueda hacia atrás no debe ser ilimitada (sin operadores * o +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Aserción negativa de búsqueda hacia atrás. Verdadero si el patrón entre paréntesis no coincide con el texto que precede a la posición de entrada actual, siendo el último carácter de la coincidencia el carácter de entrada justo antes de la posición actual. No altera la posición de entrada. La longitud de las posibles cadenas coincidentes del patrón de búsqueda hacia atrás no debe ser ilimitada (sin operadores * o +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Configuración de banderas. Evalúa la expresión entre paréntesis con las banderas especificadas habilitadas o -deshabilitadas. Las banderas se definen en Opciones de Banderas.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Configuración de banderas. Cambia la configuración de las banderas. Los cambios se aplican a la porción del patrón que sigue a la configuración. Por ejemplo, (?i) cambia a una coincidencia insensible a mayúsculas y minúsculas. Las banderas se definen en Opciones de Banderas.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/fr.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un BELL, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au début de l'entrée. Diffère de ^ en ce que \\A ne correspond pas après une nouvelle ligne dans l'entrée.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond si la position actuelle est une limite de mot. Les limites se produisent aux transitions entre les caractères de mot (\\w) et de non-mot (\\W), les marques combinées étant ignorées. Pour de meilleures limites de mots, voir useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond si la position actuelle n'est pas une limite de mot.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un caractère control-X</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à tout caractère de la catégorie générale Unicode Nd (Number, Decimal Digit).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à tout caractère qui n'est pas un chiffre décimal.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un ESCAPE, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Termine une séquence citée \\Q ... \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un FORM FEED, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond si la position actuelle est à la fin de la correspondance précédente.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un LINE FEED, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au caractère nommé.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à tout caractère avec la propriété Unicode spécifiée.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à tout caractère n'ayant pas la propriété Unicode spécifiée.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Cite tous les caractères suivants jusqu'à \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un CARRIAGE RETURN, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un caractère d'espacement. L'espace est défini comme [\\t\\n\\f\\r\\p{Z}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un caractère non-espace.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à une TABULATION HORIZONTALE, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au caractère avec la valeur hexadécimale hhhh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au caractère avec la valeur hexadécimale hhhhhhhh. Exactement huit chiffres hexadécimaux doivent être fournis, même si le plus grand point de code Unicode est \\U0010ffff.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un caractère de mot. Les caractères de mot sont [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un caractère non-mot.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au caractère avec la valeur hexadécimale hhhh. De un à six chiffres hexadécimaux peuvent être fournis.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au caractère avec la valeur hexadécimale à deux chiffres hh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un groupe de graphèmes.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond si la position actuelle est à la fin de l'entrée, mais avant le terminateur de ligne final, s'il en existe un.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond si la position actuelle est à la fin de l'entrée.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Référence arrière. Correspond à ce que le nième groupe de capture a correspondu. n doit être un nombre ≥ 1 et ≤ nombre total de groupes de capture dans le motif.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à un caractère octal. ooo va de un à trois chiffres octaux. 0377 est le plus grand caractère octal autorisé. Le zéro initial est requis ; il distingue les constantes octales des références arrière.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à n'importe quel caractère du motif.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à n'importe quel caractère.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au début d'une ligne.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond à la fin d'une ligne.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Cite le caractère suivant. Les caractères qui doivent être cités pour être traités comme des littéraux sont * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternance. A|B correspond à A ou B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond 0 fois ou plus. Correspond autant de fois que possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond 1 fois ou plus. Correspond autant de fois que possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond zéro ou une fois. Préfère une fois.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond exactement n fois.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au moins n fois. Correspond autant de fois que possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond entre n et m fois. Correspond autant de fois que possible, mais pas plus de m fois.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond 0 fois ou plus. Correspond aussi peu de fois que possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond 1 fois ou plus. Correspond aussi peu de fois que possible.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond zéro ou une fois. Préfère zéro.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond exactement n fois.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au moins n fois, mais pas plus que nécessaire pour une correspondance globale du motif.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond entre n et m fois. Correspond aussi peu de fois que possible, mais pas moins de n fois.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond 0 fois ou plus. Correspond autant de fois que possible lors de la première rencontre, ne réessaie pas avec moins même si la correspondance globale échoue (Correspondance possessive).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond 1 fois ou plus. Correspondance possessive.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond zéro ou une fois. Correspondance possessive.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond exactement n fois.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond au moins n fois. Correspondance possessive.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Correspond entre n et m fois. Correspondance possessive.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Parenthèses de capture. La plage d'entrée qui correspond à la sous-expression entre parenthèses est disponible après la correspondance.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Parenthèses non capturantes. Groupe le motif inclus, mais ne fournit pas de capture du texte correspondant. Légèrement plus efficace que les parenthèses de capture.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Parenthèses de correspondance atomique. La première correspondance de la sous-expression entre parenthèses est la seule tentée ; si elle ne mène pas à une correspondance globale du motif, revient à la recherche d'une correspondance à une position avant le &quot;(?&gt;&quot;</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Commentaire en format libre (?# commentaire ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Assertion de pré-vérification. Vrai si le motif entre parenthèses correspond à la position d'entrée actuelle, mais n'avance pas la position d'entrée.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Assertion de pré-vérification négative. Vrai si le motif entre parenthèses ne correspond pas à la position d'entrée actuelle. N'avance pas la position d'entrée.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Assertion de post-vérification. Vrai si le motif entre parenthèses correspond au texte précédant la position d'entrée actuelle, le dernier caractère de la correspondance étant le caractère d'entrée juste avant la position actuelle. Ne modifie pas la position d'entrée. La longueur des chaînes possibles correspondantes au motif de post-vérification ne doit pas être illimitée (pas d'opérateurs * ou +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Assertion de post-vérification négative. Vrai si le motif entre parenthèses ne correspond pas au texte précédant la position d'entrée actuelle, le dernier caractère de la correspondance étant le caractère d'entrée juste avant la position actuelle. Ne modifie pas la position d'entrée. La longueur des chaînes possibles correspondantes au motif de post-vérification ne doit pas être illimitée (pas d'opérateurs * ou +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Paramètres de drapeaux. Évalue l'expression entre parenthèses avec les drapeaux spécifiés activés ou -désactivés. Les drapeaux sont définis dans les Options de Drapeaux.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Paramètres de drapeaux. Modifie les paramètres de drapeaux. Les modifications s'appliquent à la partie du motif suivant le paramètre. Par exemple, (?i) passe à une correspondance insensible à la casse. Les drapeaux sont définis dans les Options de Drapeaux.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/it.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un BELL, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde all'inizio dell'input. Differisce da ^ in quanto \\A non corrisponderà dopo una nuova riga all'interno dell'input.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde se la posizione corrente è un limite di parola. I limiti si verificano alle transizioni tra caratteri di parola (\\w) e non-parola (\\W), con i segni combinati ignorati. Per migliori limiti di parola, vedere useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde se la posizione corrente non è un limite di parola.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un carattere control-X</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a qualsiasi carattere con la categoria generale Unicode Nd (Number, Decimal Digit).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a qualsiasi carattere che non è una cifra decimale.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un ESCAPE, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Termina una sequenza citata \\Q ... \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un FORM FEED, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde se la posizione corrente è alla fine della corrispondenza precedente.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un LINE FEED, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde al carattere nominato.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a qualsiasi carattere con la proprietà Unicode specificata.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a qualsiasi carattere che non ha la proprietà Unicode specificata.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Cita tutti i caratteri seguenti fino a \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un CARRIAGE RETURN, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un carattere di spaziatura. Lo spazio è definito come [\\t\\n\\f\\r\\p{Z}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un carattere non-spazio.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a una TABULAZIONE ORIZZONTALE, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde al carattere con il valore esadecimale hhhh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde al carattere con il valore esadecimale hhhhhhhh. Devono essere fornite esattamente otto cifre esadecimali, anche se il punto di codice Unicode più grande è \\U0010ffff.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un carattere di parola. I caratteri di parola sono [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un carattere non-parola.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde al carattere con il valore esadecimale hhhh. Possono essere fornite da una a sei cifre esadecimali.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde al carattere con il valore esadecimale a due cifre hh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un cluster di grafemi.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde se la posizione corrente è alla fine dell'input, ma prima del terminatore di riga finale, se esiste.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde se la posizione corrente è alla fine dell'input.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Riferimento all'indietro. Corrisponde a ciò che ha corrisposto l'ennesimo gruppo di cattura. n deve essere un numero ≥ 1 e ≤ numero totale di gruppi di cattura nel pattern.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a un carattere ottale. ooo va da uno a tre cifre ottali. 0377 è il più grande carattere ottale consentito. Lo zero iniziale è richiesto; distingue le costanti ottali dai riferimenti all'indietro.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a qualsiasi carattere del pattern.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde a qualsiasi carattere.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde all'inizio di una riga.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde alla fine di una riga.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Cita il carattere seguente. I caratteri che devono essere citati per essere trattati come letterali sono * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternanza. A|B corrisponde ad A o B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde 0 o più volte. Corrisponde il maggior numero di volte possibile.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde 1 o più volte. Corrisponde il maggior numero di volte possibile.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde zero o una volta. Preferisce una volta.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde esattamente n volte.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde almeno n volte. Corrisponde il maggior numero di volte possibile.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde tra n e m volte. Corrisponde il maggior numero di volte possibile, ma non più di m volte.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde 0 o più volte. Corrisponde il minor numero di volte possibile.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde 1 o più volte. Corrisponde il minor numero di volte possibile.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde zero o una volta. Preferisce zero.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde esattamente n volte.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde almeno n volte, ma non più di quanto richiesto per una corrispondenza complessiva del pattern.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde tra n e m volte. Corrisponde il minor numero di volte possibile, ma non meno di n volte.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde 0 o più volte. Corrisponde il maggior numero di volte possibile al primo incontro, non riprova con meno anche se la corrispondenza complessiva fallisce (Corrispondenza possessiva).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde 1 o più volte. Corrispondenza possessiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde zero o una volta. Corrispondenza possessiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde esattamente n volte.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde almeno n volte. Corrispondenza possessiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Corrisponde tra n e m volte. Corrispondenza possessiva.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Parentesi di cattura. L'intervallo di input che corrisponde alla sottoespressione tra parentesi è disponibile dopo la corrispondenza.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Parentesi non catturanti. Raggruppa il pattern incluso, ma non fornisce la cattura del testo corrispondente. Leggermente più efficiente delle parentesi di cattura.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Parentesi di corrispondenza atomica. La prima corrispondenza della sottoespressione tra parentesi è l'unica tentata; se non porta a una corrispondenza complessiva del pattern, torna alla ricerca di una corrispondenza a una posizione prima del &quot;(?&gt;&quot;</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Commento in formato libero (?# commento ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Asserzione di anticipazione positiva. Vero se il pattern tra parentesi corrisponde alla posizione di input corrente, ma non avanza la posizione di input.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Asserzione di anticipazione negativa. Vero se il pattern tra parentesi non corrisponde alla posizione di input corrente. Non avanza la posizione di input.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Asserzione di lookbehind. Vero se il pattern tra parentesi corrisponde al testo che precede la posizione di input corrente, con l'ultimo carattere della corrispondenza che è il carattere di input appena prima della posizione corrente. Non altera la posizione di input. La lunghezza delle stringhe possibili corrispondenti al pattern di lookbehind non deve essere illimitata (nessun operatore * o +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Asserzione di lookbehind negativa. Vero se il pattern tra parentesi non corrisponde al testo che precede la posizione di input corrente, con l'ultimo carattere della corrispondenza che è il carattere di input appena prima della posizione corrente. Non altera la posizione di input. La lunghezza delle stringhe possibili corrispondenti al pattern di lookbehind non deve essere illimitata (nessun operatore * o +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Impostazioni di flag. Valuta l'espressione tra parentesi con i flag specificati abilitati o -disabilitati. I flag sono definiti nelle Opzioni di Flag.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Impostazioni di flag. Modifica le impostazioni di flag. Le modifiche si applicano alla parte del pattern che segue l'impostazione. Ad esempio, (?i) passa a una corrispondenza non sensibile alle maiuscole. I flag sono definiti nelle Opzioni di Flag.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/ja.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>BELL、\\u0007にマッチします</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>入力の開始にマッチします。^とは異なり、\\Aは入力内の改行後にはマッチしません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>現在位置が単語境界の場合にマッチします。境界は単語文字(\\w)と非単語文字(\\W)の間の遷移で発生し、結合文字は無視されます。より良い単語境界については、useUnicodeWordBoundariesを参照してください。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>[集合]内でBACKSPACE、\\u0008にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>現在位置が単語境界でない場合にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>コントロール-X文字にマッチします</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Unicode汎用カテゴリNd（数字、十進数字）の任意の文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>十進数字以外の任意の文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>ESCAPE、\\u001Bにマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>\\Q ... \\Eクォートされたシーケンスを終了します。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>FORM FEED、\\u000Cにマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>現在位置が前回のマッチの終端にある場合にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>LINE FEED、\\u000Aにマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>指定された名前の文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>指定されたUnicodeプロパティを持つ任意の文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>指定されたUnicodeプロパティを持たない任意の文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>\\Eまで後続の全ての文字をクォートします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>CARRIAGE RETURN、\\u000Dにマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>空白文字にマッチします。空白文字は[\\t\\n\\f\\r\\p{Z}]として定義されます。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>非空白文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>HORIZONTAL TABULATION、\\u0009にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>16進値hhhhの文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>16進値hhhhhhhhの文字にマッチします。最大のUnicodeコードポイントが\\U0010ffffであっても、正確に8桁の16進数を指定する必要があります。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>単語文字にマッチします。単語文字は[\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}]です。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>非単語文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>16進値hhhhの文字にマッチします。1桁から6桁まで指定できます。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>2桁の16進値hhの文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>書記素クラスターにマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>現在位置が入力の終端にあり、かつ最終行終端記号がある場合はその直前の位置にある場合にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>現在位置が入力の終端にある場合にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>後方参照。n番目のキャプチャグループがマッチした内容と同じものにマッチします。nはパターン内のキャプチャグループ総数以下かつ1以上の数値である必要があります。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>8進文字にマッチします。oooは1桁から3桁の8進数字です。0377が許可される最大の8進文字です。先頭のゼロは必須で、8進定数と後方参照を区別します。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>パターン内の任意の1文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>任意の文字にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>行の開始にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>行の終端にマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>後続の文字をクォートします。リテラルとして扱うためにクォートが必要な文字は * ? + [ ( ) { } ^ $ | \\ . / です</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>選択。A|BはAまたはBのいずれかにマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0回以上マッチします。可能な限り多くマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>1回以上マッチします。可能な限り多くマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0回または1回マッチします。1回を優先します。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>正確にn回マッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>最低n回マッチします。可能な限り多くマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>n回からm回までマッチします。可能な限り多くマッチしますが、m回を超えません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0回以上マッチします。可能な限り少なくマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>1回以上マッチします。可能な限り少なくマッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0回または1回マッチします。0回を優先します。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>正確にn回マッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>最低n回マッチしますが、全体のパターンマッチに必要な回数を超えません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>n回からm回までマッチします。可能な限り少なくマッチしますが、n回未満にはなりません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0回以上マッチします。初回時に可能な限り多くマッチし、全体のマッチが失敗しても、より少ないマッチで再試行しません（占有マッチ）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>1回以上マッチします。占有マッチです。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0回または1回マッチします。占有マッチです。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>正確にn回マッチします。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>最低n回マッチします。占有マッチです。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>n回からm回までマッチします。占有マッチです。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>キャプチャ括弧。括弧内のサブ式にマッチした入力の範囲は、マッチ後に使用可能です。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>非キャプチャ括弧。含まれるパターンをグループ化しますが、マッチしたテキストのキャプチャは行いません。キャプチャ括弧よりもやや効率的です。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>アトミックマッチ括弧。括弧内のサブ式の最初のマッチのみを試し、全体のパターンマッチにつながらない場合は&quot;(?&gt;&quot;の直前の位置までバックアップします</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>自由形式コメント (?# comment )。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>先読みアサーション。括弧内のパターンが現在の入力位置でマッチする場合はtrueですが、入力位置は進みません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>否定先読みアサーション。括弧内のパターンが現在の入力位置でマッチしない場合はtrueです。入力位置は進みません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>後読みアサーション。括弧内のパターンが現在の入力位置の前のテキストにマッチし、マッチの最後の文字が現在位置の直前の入力文字である場合はtrueです。入力位置は変更されません。後読みパターンによってマッチされる可能性のある文字列の長さは無制限であってはなりません（*や+演算子は使用できません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>否定後読みアサーション。括弧内のパターンが現在の入力位置の前のテキストにマッチせず、マッチの最後の文字が現在位置の直前の入力文字である場合はtrueです。入力位置は変更されません。後読みパターンによってマッチされる可能性のある文字列の長さは無制限であってはなりません（*や+演算子は使用できません。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>フラグ設定。指定されたフラグを有効または-無効にして括弧内の式を評価します。フラグはFlag Optionsで定義されています。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>フラグ設定。フラグ設定を変更します。変更は設定以降のパターン部分に適用されます。例えば、(?i)は大文字小文字を区別しないマッチに変更します。フラグはFlag Optionsで定義されています。</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/ko.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>BELL 문자와 일치, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>입력의 시작 부분과 일치합니다. 입력 내 줄바꿈 후에는 일치하지 않는다는 점에서 ^와 다릅니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>현재 위치가 단어 경계인 경우 일치합니다. 경계는 결합 표시를 무시하고 단어(\\w)와 비단어(\\W) 문자 간의 전환에서 발생합니다. 더 나은 단어 경계를 원하면 useUnicodeWordBoundaries를 참조하세요.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>BACKSPACE와 일치, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>현재 위치가 단어 경계가 아닌 경우 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>제어-X 문자와 일치합니다</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>유니코드 일반 범주가 Nd(숫자, 10진수)인 모든 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>10진수가 아닌 모든 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>ESCAPE와 일치, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>\\Q ... \\E 인용 시퀀스를 종료합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>FORM FEED와 일치, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>현재 위치가 이전 일치의 끝에 있는 경우 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>LINE FEED와 일치, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>명명된 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>지정된 유니코드 속성을 가진 모든 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>지정된 유니코드 속성을 갖지 않은 모든 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>\\E까지 다음 모든 문자를 인용합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>CARRIAGE RETURN과 일치, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>공백 문자와 일치합니다. 공백은 [\\t\\n\\f\\r\\p{Z}]로 정의됩니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>공백이 아닌 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>HORIZONTAL TABULATION과 일치, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>16진수 값 hhhh를 가진 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>16진수 값 hhhhhhhh를 가진 문자와 일치합니다. 가장 큰 유니코드 코드 포인트가 \\U0010ffff이더라도 정확히 8개의 16진수를 제공해야 합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>단어 문자와 일치합니다. 단어 문자는 [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}]입니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>단어가 아닌 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>16진수 값 hhhh를 가진 문자와 일치합니다. 1개에서 6개의 16진수를 제공할 수 있습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>두 자리 16진수 값 hh를 가진 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>자소 클러스터와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>현재 위치가 입력의 끝에 있지만 최종 줄 종결자가 있는 경우 그 앞에 있으면 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>현재 위치가 입력의 끝에 있으면 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>역참조. n번째 캡처 그룹이 일치한 내용과 일치합니다. n은 ≥ 1이고 패턴의 총 캡처 그룹 수 ≤인 숫자여야 합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>8진수 문자와 일치합니다. ooo는 1개에서 3개의 8진수입니다. 0377은 허용되는 가장 큰 8진수 문자입니다. 앞의 0은 필수이며 8진수 상수를 역참조와 구별합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>패턴의 모든 문자 중 하나와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>모든 문자와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>줄의 시작 부분과 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>줄의 끝 부분과 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>다음 문자를 인용합니다. 리터럴로 처리되기 위해 인용해야 하는 문자는 * ? + [ ( ) { } ^ $ | \\ . /입니다</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>대체. A|B는 A 또는 B와 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0회 이상 일치합니다. 가능한 한 많이 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>1회 이상 일치합니다. 가능한 한 많이 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0회 또는 1회 일치합니다. 1회를 선호합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>정확히 n회 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>최소 n회 일치합니다. 가능한 한 많이 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>n회에서 m회 사이로 일치합니다. 가능한 한 많이 일치하지만 m회를 초과하지 않습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0회 이상 일치합니다. 가능한 한 적게 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>1회 이상 일치합니다. 가능한 한 적게 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0회 또는 1회 일치합니다. 0회를 선호합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>정확히 n회 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>최소 n회 일치하지만 전체 패턴 일치에 필요한 것보다 많지 않습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>n회에서 m회 사이로 일치합니다. 가능한 한 적게 일치하지만 n회보다 적지 않습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0회 이상 일치합니다. 처음 발견했을 때 가능한 한 많이 일치하고, 전체 일치가 실패하더라도 더 적게 재시도하지 않습니다(소유 일치).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>1회 이상 일치합니다. 소유 일치.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>0회 또는 1회 일치합니다. 소유 일치.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>정확히 n회 일치합니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>최소 n회 일치합니다. 소유 일치.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>n회에서 m회 사이로 일치합니다. 소유 일치.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>캡처 괄호. 괄호로 묶인 하위 표현식과 일치하는 입력 범위는 일치 후에 사용할 수 있습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>비캡처 괄호. 포함된 패턴을 그룹화하지만 일치하는 텍스트의 캡처를 제공하지 않습니다. 캡처 괄호보다 다소 효율적입니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>원자 일치 괄호. 괄호로 묶인 하위 표현식의 첫 번째 일치만 시도됩니다. 전체 패턴 일치로 이어지지 않으면 \"(?&gt;\" 앞의 위치로 일치 검색을 백업합니다</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>자유 형식 주석 (?# comment ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>전방 탐색 어서션. 괄호로 묶인 패턴이 현재 입력 위치와 일치하지만 입력 위치를 진행하지 않으면 참입니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>부정 전방 탐색 어서션. 괄호로 묶인 패턴이 현재 입력 위치와 일치하지 않으면 참입니다. 입력 위치를 진행하지 않습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>후방 탐색 어서션. 괄호로 묶인 패턴이 현재 입력 위치 앞의 텍스트와 일치하고 일치의 마지막 문자가 현재 위치 바로 앞의 입력 문자인 경우 참입니다. 입력 위치를 변경하지 않습니다. 후방 탐색 패턴과 일치할 수 있는 문자열의 길이는 무제한이 아니어야 합니다(* 또는 + 연산자 없음).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>부정 후방 탐색 어서션. 괄호로 묶인 패턴이 현재 입력 위치 앞의 텍스트와 일치하지 않고 일치의 마지막 문자가 현재 위치 바로 앞의 입력 문자인 경우 참입니다. 입력 위치를 변경하지 않습니다. 후방 탐색 패턴과 일치할 수 있는 문자열의 길이는 무제한이 아니어야 합니다(* 또는 + 연산자 없음).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>플래그 설정. 지정된 플래그가 활성화되거나 -비활성화된 상태에서 괄호로 묶인 표현식을 평가합니다. 플래그는 플래그 옵션에 정의되어 있습니다.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>플래그 설정. 플래그 설정을 변경합니다. 변경 사항은 설정 다음의 패턴 부분에 적용됩니다. 예를 들어 (?i)는 대소문자를 구분하지 않는 일치로 변경합니다. 플래그는 플래그 옵션에 정의되어 있습니다.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/nl.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een BELL, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met het begin van de invoer. Verschilt van ^ doordat \\A niet overeenkomt na een nieuwe regel in de invoer.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen als de huidige positie een woordgrens is. Grenzen treden op bij overgangen tussen woord- (\\w) en niet-woord- (\\W) tekens, waarbij combinerende markeringen worden genegeerd. Voor betere woordgrenzen, zie useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen als de huidige positie geen woordgrens is.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een control-X teken</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met elk teken met de Unicode Algemene Categorie Nd (Getal, Decimaal Cijfer.)</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met elk teken dat geen decimaal cijfer is.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een ESCAPE, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Beëindigt een \\Q ... \\E geciteerde reeks.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een FORM FEED, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen als de huidige positie aan het einde van de vorige overeenkomst is.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een LINE FEED, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met het benoemde teken.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met elk teken met de opgegeven Unicode-eigenschap.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met elk teken dat niet de opgegeven Unicode-eigenschap heeft.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Citeert alle volgende tekens tot \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een CARRIAGE RETURN, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een witruimte-teken. Witruimte is gedefinieerd als [\\t\\n\\f\\r\\p{Z}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een niet-witruimte-teken.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een HORIZONTALE TABULATIE, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met het teken met de hex-waarde hhhh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met het teken met de hex-waarde hhhhhhhh. Er moeten precies acht hex-cijfers worden opgegeven, ook al is het grootste Unicode-codepunt \\U0010ffff.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een woordteken. Woordtekens zijn [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een niet-woordteken.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met het teken met de hex-waarde hhhh. Er kunnen één tot zes hex-cijfers worden opgegeven.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met het teken met de tweecijferige hex-waarde hh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een Grafeemcluster.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen als de huidige positie aan het einde van de invoer is, maar voor de laatste regeleenheid, als die bestaat.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen als de huidige positie aan het einde van de invoer is.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Terugverwijzing. Komt overeen met wat de n-de vastleggroep heeft gevonden. n moet een getal ≥ 1 en ≤ het totale aantal vastleggroepen in het patroon zijn.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met een octaal teken. ooo is één tot drie octale cijfers. 0377 is het grootste toegestane octale teken. De leidende nul is vereist; deze onderscheidt octale constanten van terugverwijzingen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met elk willekeurig teken uit het patroon.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen met elk willekeurig teken.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen aan het begin van een regel.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt overeen aan het einde van een regel.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Citeert het volgende teken. Tekens die geciteerd moeten worden om als letterlijk te worden behandeld zijn * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternatie. A|B komt overeen met A of B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt 0 of meer keer overeen. Komt zo vaak mogelijk overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt 1 of meer keer overeen. Komt zo vaak mogelijk overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt nul of één keer overeen. Voorkeur voor één.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt precies n keer overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt ten minste n keer overeen. Komt zo vaak mogelijk overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt tussen n en m keer overeen. Komt zo vaak mogelijk overeen, maar niet vaker dan m.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt 0 of meer keer overeen. Komt zo weinig mogelijk overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt 1 of meer keer overeen. Komt zo weinig mogelijk overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt nul of één keer overeen. Voorkeur voor nul.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt precies n keer overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt ten minste n keer overeen, maar niet vaker dan nodig voor een algehele patroonovereenkomst.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt tussen n en m keer overeen. Komt zo weinig mogelijk overeen, maar niet minder dan n.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt 0 of meer keer overeen. Komt zo vaak mogelijk overeen bij de eerste ontmoeting, probeer niet opnieuw met minder, zelfs niet als de algehele overeenkomst mislukt (Bezitterige Overeenkomst).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt 1 of meer keer overeen. Bezitterige overeenkomst.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt nul of één keer overeen. Bezitterige overeenkomst.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt precies n keer overeen.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt ten minste n keer overeen. Bezitterige Overeenkomst.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komt tussen n en m keer overeen. Bezitterige Overeenkomst.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Vastleggende haakjes. Het bereik van de invoer dat overeenkwam met de subexpressie tussen haakjes is beschikbaar na de overeenkomst.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Niet-vastleggende haakjes. Groepeert het opgenomen patroon, maar biedt geen vastlegging van overeenkomende tekst. Iets efficiënter dan vastleggende haakjes.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Atoom-overeenkomst haakjes. De eerste overeenkomst van de subexpressie tussen haakjes is de enige die wordt geprobeerd; als dit niet leidt tot een algehele patroonovereenkomst, ga dan terug naar een positie voor de &quot;(?&gt;&quot;</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Vrij-formaat commentaar (?# commentaar ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Look-ahead bewering. Waar als het patroon tussen haakjes overeenkomt op de huidige invoerpositie, maar de invoerpositie niet opschuift.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negatieve look-ahead bewering. Waar als het patroon tussen haakjes niet overeenkomt op de huidige invoerpositie. Schuift de invoerpositie niet op.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Look-behind bewering. Waar als het patroon tussen haakjes overeenkomt met tekst die voorafgaat aan de huidige invoerpositie, waarbij het laatste teken van de overeenkomst het invoerteken is vlak voor de huidige positie. Verandert de invoerpositie niet. De lengte van mogelijke tekenreeksen die overeenkomen met het look-behind patroon mag niet onbegrensd zijn (geen * of + operatoren).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negatieve look-behind bewering. Waar als het patroon tussen haakjes niet overeenkomt met tekst die voorafgaat aan de huidige invoerpositie, waarbij het laatste teken van de overeenkomst het invoerteken is vlak voor de huidige positie. Verandert de invoerpositie niet. De lengte van mogelijke tekenreeksen die overeenkomen met het look-behind patroon mag niet onbegrensd zijn (geen * of + operatoren).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Vlaginstellingen. Evalueer de expressie tussen haakjes met de opgegeven vlaggen ingeschakeld of -uitgeschakeld. De vlaggen zijn gedefinieerd in Vlagopties.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Vlaginstellingen. Wijzig de vlaginstellingen. Wijzigingen zijn van toepassing op het deel van het patroon dat volgt op de instelling. Bijvoorbeeld, (?i) wijzigt in een hoofdletterongevoelige overeenkomst. De vlaggen zijn gedefinieerd in Vlagopties.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/pl.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dzwonka (BELL), \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie na początku wejścia. Różni się od ^ tym, że \\A nie dopasuje po nowej linii wewnątrz wejścia.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, outside of a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie, jeśli obecna pozycja jest granicą słowa. Granice występują na przejściach między znakami słownymi (\\w) i niesłownymi (\\W), z pominięciem znaków łączących. Dla lepszych granic słów zobacz useUnicodeWordBoundaries.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, within a [Set]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku BACKSPACE, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie, jeśli obecna pozycja nie jest granicą słowa.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku control-X</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dowolnego znaku z kategorii Unicode Nd (Liczba, cyfra dziesiętna).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dowolnego znaku, który nie jest cyfrą dziesiętną.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku ESCAPE, \\u001B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Kończy sekwencję cytowaną \\Q ... \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku FORM FEED, \\u000C.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie, jeśli obecna pozycja znajduje się na końcu poprzedniego dopasowania.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku LINE FEED, \\u000A.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie nazwanego znaku.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dowolnego znaku o określonej właściwości Unicode.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dowolnego znaku niemającego określonej właściwości Unicode.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Cytuje wszystkie następne znaki aż do \\E.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku CARRIAGE RETURN, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie białego znaku. Białe znaki to [\\t\\n\\f\\r\\p{Z}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku niebędącego białym znakiem.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie tabulacji poziomej, \\u0009.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku o wartości szesnastkowej hhhh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku o wartości szesnastkowej hhhhhhhh. Należy podać dokładnie osiem cyfr szesnastkowych, mimo że największym punktem kodowym Unicode jest \\U0010ffff.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku słowa. Znaki słowa to [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}].</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku niebędącego znakiem słowa.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku o wartości szesnastkowej hhhh. Można podać od jednej do sześciu cyfr szesnastkowych.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku o dwucyfrowej wartości szesnastkowej hh.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie klastra grafemów.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie, jeśli obecna pozycja znajduje się na końcu wejścia, ale przed końcowym separatorem linii, jeśli taki istnieje.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie, jeśli obecna pozycja znajduje się na końcu wejścia.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Referencja wsteczna. Dopasowuje to, co dopasowała n-ta grupa przechwytująca. n musi być liczbą ≥ 1 i ≤ całkowitej liczbie grup przechwytujących w rzędzie.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie znaku ósemkowego. ooo to od jednej do trzech cyfr ósemkowych. 0377 to największy dozwolony znak ósemkowy. Wymagane jest zero wiodące; odróżnia ono stałe ósemkowe od referencji wstecznych.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dowolnego pojedynczego znaku z wzorca.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dowolnego znaku.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie na początku linii.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie na końcu linii.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Cytuje następny znak. Znaki, które muszą być cytowane, aby być traktowane dosłownie, to * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Alternatywa. A|B dopasowuje albo A, albo B.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie 0 lub więcej razy. Dopasowuje tak wiele razy, jak to możliwe.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie 1 lub więcej razy. Dopasowuje tak wiele razy, jak to możliwe.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie zero lub jeden raz. Preferuje jeden.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dokładnie n razy.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie co najmniej n razy. Dopasowuje tak wiele razy, jak to możliwe.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie od n do m razy. Dopasowuje tak wiele razy, jak to możliwe, ale nie więcej niż m.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie 0 lub więcej razy. Dopasowuje tak mało razy, jak to możliwe.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie 1 lub więcej razy. Dopasowuje tak mało razy, jak to możliwe.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie zero lub jeden raz. Preferuje zero.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dokładnie n razy.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie co najmniej n razy, ale nie więcej niż wymaga dopasowanie całego wzorca.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie od n do m razy. Dopasowuje tak mało razy, jak to możliwe, ale nie mniej niż n.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie 0 lub więcej razy. Dopasowuje tak wiele razy, jak to możliwe przy pierwszym napotkaniu, nie próbuje ponownie z mniejszą liczbą, nawet jeśli całe dopasowanie się nie powiedzie (dopasowanie zachłanne/posesywne).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie 1 lub więcej razy. Dopasowanie posesywne.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie zero lub jeden raz. Dopasowanie posesywne.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie dokładnie n razy.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie co najmniej n razy. Dopasowanie posesywne.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Dopasowanie od n do m razy. Dopasowanie posesywne.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Nawiasy przechwytujące. Zakres wejścia, który pasował do podwyrażenia w nawiasach, jest dostępny po dopasowaniu.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Nawiasy nieprzechwytujące. Grupuje zawarty wzorzec, ale nie zapewnia przechwytywania dopasowanego tekstu. Nieco bardziej wydajne niż nawiasy przechwytujące.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Nawiasy dopasowania atomowego. Wypróbowywane jest tylko pierwsze dopasowanie podwyrażenia w nawiasach; jeśli nie prowadzi ono do dopasowania całego wzorca, wyszukiwanie jest cofane do pozycji przed &quot;(?&gt;&quot;</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Komentarz o dowolnym formacie (?# komentarz ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Asercja look-ahead (wyprzedzająca). Prawda, jeśli wzorzec w nawiasach pasuje w bieżącej pozycji wejściowej, ale nie przesuwa pozycji wejściowej.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negatywna asercja look-ahead. Prawda, jeśli wzorzec w nawiasach nie pasuje w bieżącej pozycji wejściowej. Nie przesuwa pozycji wejściowej.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Asercja look-behind (wsteczna). Prawda, jeśli wzorzec w nawiasach pasuje do tekstu poprzedzającego bieżącą pozycję wejściową, przy czym ostatni znak dopasowania jest znakiem wejściowym tuż przed bieżącą pozycją. Nie zmienia pozycji wejściowej. Długość możliwych ciągów pasujących do wzorca look-behind nie może być nieograniczona (brak operatorów * lub +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Negatywna asercja look-behind. Prawda, jeśli wzorzec w nawiasach nie pasuje do tekstu poprzedzającego bieżącą pozycję wejściową, przy czym ostatni znak dopasowania jest znakiem wejściowym tuż przed bieżącą pozycją. Nie zmienia pozycji wejściowej. Długość możliwych ciągów pasujących do wzorca look-behind nie może być nieograniczona (brak operatorów * lub +).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Ustawienia flag. Ewaluuje wyrażenie w nawiasach z włączonymi lub wyłączonymi (-) określonymi flagami. Flagi są zdefiniowane w Opcjach Flag.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>Ustawienia flag. Zmienia ustawienia flag. Zmiany dotyczą części wzorca następującej po ustawieniu. Na przykład (?i) zmienia na dopasowanie niewrażliwe na wielkość liter. Flagi są zdefiniowane w Opcjach Flag.</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/zh-Hans.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个警报声, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配输入的开端。和 ^ 不同的是，\\A 不会匹配换行后的开端。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, 在 [集合] 外</string>\n\t\t\t<key>des</key>\n\t\t\t<string>当前位置是词语边界时匹配。词语边界是指词语 (\\w) 和非词语 (\\W) 字符之间的界限，这种边界会忽略连字符。为了更好地使用词语边界，请打开『使用 unicode 词语边界』选项。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, 在 [集合] 内</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个退格, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>当前位置不是词语边界时匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个 control-X 字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任何符合 Unicode 通用类别的数字字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任何不为数字的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个 ESCAPE, \\u001B。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>终止一个 \\Q ... \\E 元字符引用序列。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配换页符, \\u000C。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>当前位置是上一个匹配的结束位置时匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个换行符, \\u000A。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 Unicode 命名字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任意有指定 Unicode 属性的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任意不包括指定 Unicode 属性的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>开始元字符引用序列，直到遇到 \\E。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个 &lt;CR&gt; 回车, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个空白字符，它的定义是 [\\t\\n\\f\\r\\p{Z}]。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个非空白字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个横向 TAB 缩进，\\u0009。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值为 hhhh 的字符串。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值为 hhhhhhhh 的字符串。尽管最大的 Unicode 值是 \\U0010ffff，但还是要提供完整的八个十六进制数字。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个词语字符，它的字符定义是 [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}]。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个非词语字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值为 hhhh 的字符串，可以是一到六位的十六进制数字。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值为 hh 的两位十六进制数字对应的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个字符簇（Grapheme Cluster）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>当前位置是输入的结尾时匹配，但仅匹配到行尾标识前，如果有的话。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>当前位置是输入的结尾时匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>换行引用。无论第 n 个捕获组匹配到什么，n 必须是一个 ≥ 1 并 ≤ 总捕获数的数字。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一个八进制字符。ooo 为一个到三个八进制数字。0377 是有效的最大八进制字符。前置的零是必须的；它将八进制常量与之后的引用值区分开来。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任何在这个方括号内的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配所有字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配行首。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配行尾。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>转义后续字符。有些字符必须转义后才能被当成字面量使用，如 * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>可选匹配。A|B 表示是 A 或者是 B 的一个字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或多次，优先匹配多次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一次或多次，优先匹配多次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零到一次，优先匹配一次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>明确匹配 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配最少 n 次，最多无限次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 n 到 m 次，优先匹配尽可能多的次数，但不会超过 m 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或多次，尽可能少匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一次或多次，尽可能少匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或一次，尽可能少匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>明确匹配 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配至少 n 次，但不超过整体模式匹配的要求。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 n 到 m 次，尽可能少匹配，但不少于 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或以上。第一次遇到时，尽量多匹配，即使整体匹配失败，也不要用较少的次数重试（独占模式）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一次或多次，独占模式。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或一次，独占模式。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>明确匹配 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配至少 n 次，独占模式，匹配得越多越好。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 n 到 m 次，独占模式，匹配得越多越好。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>圆括号匹配。整个表达式匹配结束后，圆括号内的子表达式所捕获到的区域能从匹配信息中单独获得。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>非捕获圆括号。匹配括号内冒号之后的表达式但不做捕获，无法从匹配信息中获得，某些时候比捕获圆括号更加高效。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>原子匹配圆括号。括号子表达式的第一次匹配是唯一一次尝试；如果没有导致整体模式匹配，则搜索匹配回到 &quot;(?&gt;&quot; 之前的位置。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>自由格式的注释 (?# 注释 ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>向后断言。当括号内的表达式在当前输入位置匹配时生效，但不移动输入位置。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>否定的向后断言。当括号内的表达式在当前输入位置不匹配时生效。不移动输入位置。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>向前断言。如果括号内的表达式与当前输入位置之前的文本相匹配，且匹配的最后一个字符是当前位置之前的输入字符，则生效，且不改变输入位置。向前断言模式匹配的字符串长度不能是无限制的（没有 * 或 + 运算符）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>否定的向前断言。如果括号内的表达式与当前输入位置之前的文本不匹配，则生效，匹配的最后一个字符是当前位置之前的输入字符。不改变输入位置。否定的向前断言模式匹配的字符串长度不能是无限制的（没有 * 或 + 运算符）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n            <string>标志设置。在启用或禁用指定的标志时评估括号内的表达式。这些标志在标志选项中定义。例如，(?i:Aa) 启用不区分大小写，(?-i:Aa) 禁用不区分大小写。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>标志设置。更改标志设置。更改适用于设置后的模式部分。例如，(?i) 改变为不区分大小写的匹配。标志在标志选项中定义。</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+/zh-Hant.lproj/CheatSheet.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>metacharacters</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\a</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個警報聲, \\u0007</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\A</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配輸入的開端。和 ^ 不同的是，\\A 不會匹配換行後的開端。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, 在 [集合] 外</string>\n\t\t\t<key>des</key>\n\t\t\t<string>當前位置是詞語邊界時匹配。詞語邊界是指詞語 (\\w) 和非詞語 (\\W) 字符之間的界限，這種邊界會忽略連字符。為了更好地使用詞語邊界，請打開『使用 unicode 詞語邊界』選項。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\b, 在 [集合] 內</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個退格, \\u0008.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\B</string>\n\t\t\t<key>des</key>\n\t\t\t<string>當前位置不是詞語邊界時匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\cX</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個 control-X 字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\d</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任何符合 Unicode 通用類別的數字字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\D</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任何不為數字的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\e</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個 ESCAPE, \\u001B。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\E</string>\n\t\t\t<key>des</key>\n\t\t\t<string>終止一個 \\Q ... \\E 元字符引用序列。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\f</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配換頁符, \\u000C。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\G</string>\n\t\t\t<key>des</key>\n\t\t\t<string>當前位置是上一個匹配的結束位置時匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個換行符, \\u000A。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\N{UNICODE CHARACTER NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 Unicode 命名字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\p{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任意有指定 Unicode 屬性的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\P{UNICODE PROPERTY NAME}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任意不包括指定 Unicode 屬性的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Q</string>\n\t\t\t<key>des</key>\n\t\t\t<string>開始元字符引用序列，直到遇到 \\E。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\r</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個 &lt;CR&gt; 回車, \\u000D.</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\s</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個空白字符，它的定義是 [\\t\\n\\f\\r\\p{Z}]。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\S</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個非空白字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\t</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個橫向 TAB 縮進，\\u0009。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\uhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值為 hhhh 的字符串。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Uhhhhhhhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值為 hhhhhhhh 的字符串。儘管最大的 Unicode 值是 \\U0010ffff，但還是要提供完整的八個十六進制數字。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\w</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個詞語字符，它的字符定義是 [\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}]。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\W</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個非詞語字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\x{hhhh}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值為 hhhh 的字符串，可以是一到六位的十六進制數字。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\xhh</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 hex 值為 hh 的兩位十六進制數字對應的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\X</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個字符簇（Grapheme Cluster）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\Z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>當前位置是輸入的結尾時匹配，但僅匹配到行尾標識前，如果有的話。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\z</string>\n\t\t\t<key>des</key>\n\t\t\t<string>當前位置是輸入的結尾時匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\n</string>\n\t\t\t<key>des</key>\n\t\t\t<string>換行引用。無論第 n 個捕獲組匹配到什麼，n 必須是一個 ≥ 1 並 ≤ 總捕獲數的數字。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\0ooo</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一個八進制字符。ooo 為一個到三個八進制數字。0377 是有效的最大八進制字符。前置的零是必須的；它將八進制常量與之後的引用值區分開來。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>[pattern]</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配任何在這個方括號內的字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>.</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配所有字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>^</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配行首。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>$</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配行尾。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>\\</string>\n\t\t\t<key>des</key>\n\t\t\t<string>轉義後續字符。有些字符必須轉義後才能被當成字面量使用，如 * ? + [ ( ) { } ^ $ | \\ . /</string>\n\t\t</dict>\n\t</array>\n\t<key>operators</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>|</string>\n\t\t\t<key>des</key>\n\t\t\t<string>可選匹配。A|B 表示是 A 或者是 B 的一個字符。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或多次，優先匹配多次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一次或多次，優先匹配多次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零到一次，優先匹配一次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>明確匹配 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配最少 n 次，最多無限次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 n 到 m 次，優先匹配儘可能多的次數，但不會超過 m 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或多次，儘可能少匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>+?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一次或多次，儘可能少匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>??</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或一次，儘可能少匹配。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>明確匹配 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配至少 n 次，但不超過整體模式匹配的要求。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}?</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 n 到 m 次，儘可能少匹配，但不少於 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>*+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或以上。第一次遇到時，儘量多匹配，即使整體匹配失敗，也不要用較少的次數重試（獨佔模式）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>++</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配一次或多次，獨佔模式。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>?+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配零次或一次，獨佔模式。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>明確匹配 n 次。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配至少 n 次，獨佔模式，匹配得越多越好。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>{n,m}+</string>\n\t\t\t<key>des</key>\n\t\t\t<string>匹配 n 到 m 次，獨佔模式，匹配得越多越好。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>圓括號匹配。整個表達式匹配結束後，圓括號內的子表達式所捕獲到的區域能從匹配信息中單獨獲得。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?:...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>非捕獲圓括號。匹配括號內冒號之後的表達式但不做捕獲，無法從匹配信息中獲得，某些時候比捕獲圓括號更加高效。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&gt;...)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>原子匹配圓括號。括號子表達式的第一次匹配是唯一一次嘗試；如果沒有導致整體模式匹配，則搜索匹配回到 &quot;(?&gt;&quot; 之前的位置。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?# ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>自由格式的註釋 (?# 註釋 ).</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>向後斷言。當括號內的表達式在當前輸入位置匹配時生效，但不移動輸入位置。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>否定的向後斷言。當括號內的表達式在當前輸入位置不匹配時生效。不移動輸入位置。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;= ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>向前斷言。如果括號內的表達式與當前輸入位置之前的文本相匹配，且匹配的最後一個字符是當前位置之前的輸入字符，則生效，且不改變輸入位置。向前斷言模式匹配的字符串長度不能是無限制的（沒有 * 或 + 運算符）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?&lt;! ... )</string>\n\t\t\t<key>des</key>\n\t\t\t<string>否定的向前斷言。如果括號內的表達式與當前輸入位置之前的文本不匹配，則生效，匹配的最後一個字符是當前位置之前的輸入字符。不改變輸入位置。否定的向前斷言模式匹配的字符串長度不能是無限制的（沒有 * 或 + 運算符）。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx: ... )</string>\n\t\t\t<key>des</key>\n            <string>標誌設置。在啟用或禁用指定的標誌時評估括號內的表達式。這些標誌在標誌選項中定義。例如，(?i:Aa) 啟用不區分大小寫，(?-i:Aa) 禁用不區分大小寫。</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>exp</key>\n\t\t\t<string>(?ismwx-ismwx)</string>\n\t\t\t<key>des</key>\n\t\t\t<string>標誌設置。更改標誌設置。更改適用於設置後的模式部分。例如，(?i) 改變為不區分大小寫的匹配。標誌在標誌選項中定義。</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "RegEx+.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2B98B5427488929CF4B9104F /* RegExFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73E3E4B7BCD55ACE7E2C6A55 /* RegExFlowView.swift */; };\n\t\tD709006C245DB72C00326016 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D709006B245DB72C00326016 /* CloudKit.framework */; };\n\t\tD7090092245DB87C00326016 /* RegEx.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = D7090090245DB87C00326016 /* RegEx.xcdatamodeld */; };\n\t\tD71871E6245EE9AC001F1E4E /* RegExFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71871E5245EE9AC001F1E4E /* RegExFetch.swift */; };\n\t\tD71F8F10246F8E5300A11283 /* ActivityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71F8F0F246F8E5300A11283 /* ActivityViewController.swift */; };\n\t\tD721780B2451776000F17390 /* RegExTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D721780A2451776000F17390 /* RegExTextView.swift */; };\n\t\tD731F64B245EF4C500EEE17F /* RegEx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D731F649245EF4C500EEE17F /* RegEx.swift */; };\n\t\tD731F64E245EF77600EEE17F /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D731F64D245EF77600EEE17F /* DataManager.swift */; };\n\t\tD731F650245F053A00EEE17F /* LibraryView+Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = D731F64F245F053A00EEE17F /* LibraryView+Data.swift */; };\n\t\tD731F652245F0B9A00EEE17F /* LibraryItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D731F651245F0B9A00EEE17F /* LibraryItemView.swift */; };\n\t\tD731F6562460F2BA00EEE17F /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D731F6552460F2BA00EEE17F /* SafariView.swift */; };\n\t\tD74BF66D247A3C0A0032EE35 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74BF66C247A3C0A0032EE35 /* AboutView.swift */; };\n\t\tD75902AD2513C6300032013F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75902AC2513C6300032013F /* AppDelegate.swift */; };\n\t\tD75902B02513C6620032013F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75902AF2513C6620032013F /* SceneDelegate.swift */; };\n\t\tD7732029245D1877003C0CF8 /* RegExSyntaxHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7732028245D1877003C0CF8 /* RegExSyntaxHighlighter.swift */; };\n\t\tD7732033245D3388003C0CF8 /* String+NSRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7732032245D3388003C0CF8 /* String+NSRange.swift */; };\n\t\tD7732035245D3456003C0CF8 /* MatchesTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7732034245D3456003C0CF8 /* MatchesTextView.swift */; };\n\t\tD77C7970247EBC6D00D3B1B2 /* CheatSheet.plist in Resources */ = {isa = PBXBuildFile; fileRef = D77C7972247EBC6D00D3B1B2 /* CheatSheet.plist */; };\n\t\tD78E45502E4795E5002ACA56 /* AppAboutView in Frameworks */ = {isa = PBXBuildFile; productRef = D78E454F2E4795E5002ACA56 /* AppAboutView */; };\n\t\tD78E45BC2E48352B002ACA56 /* ShortcutKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E45BB2E483529002ACA56 /* ShortcutKeys.swift */; };\n\t\tD7A925DC2B81057E0023E8EA /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D7A925DB2B81057E0023E8EA /* Localizable.xcstrings */; };\n\t\tD7BB73F9244F47E400343AC5 /* EditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BB73F8244F47E400343AC5 /* EditorView.swift */; };\n\t\tD7CCA7D9244E010D00D81C74 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CCA7D8244E010D00D81C74 /* HomeView.swift */; };\n\t\tD7CCA7DB244E010F00D81C74 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D7CCA7DA244E010F00D81C74 /* Assets.xcassets */; };\n\t\tD7CCA7DE244E010F00D81C74 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D7CCA7DD244E010F00D81C74 /* Preview Assets.xcassets */; };\n\t\tD7CCA7E1244E010F00D81C74 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D7CCA7DF244E010F00D81C74 /* LaunchScreen.storyboard */; };\n\t\tD7CCA7EC244E038E00D81C74 /* LibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CCA7EB244E038E00D81C74 /* LibraryView.swift */; };\n\t\tD7CCA7EF244E041000D81C74 /* CheatSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CCA7EE244E041000D81C74 /* CheatSheetView.swift */; };\n\t\tD7DC514A2529645F00A495E2 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DC51492529645F00A495E2 /* SearchView.swift */; };\n\t\tD7EF735A2453E7FB005974F0 /* EditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF73592453E7FB005974F0 /* EditorViewModel.swift */; };\n\t\tD7F100012F100001002ACA56 /* _RegexParser in Frameworks */ = {isa = PBXBuildFile; productRef = D7F100032F100001002ACA56 /* _RegexParser */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t73E3E4B7BCD55ACE7E2C6A55 /* RegExFlowView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RegExFlowView.swift; sourceTree = \"<group>\"; };\n\t\tD709006B245DB72C00326016 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };\n\t\tD7090091245DB87C00326016 /* RegEx.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = RegEx.xcdatamodel; sourceTree = \"<group>\"; };\n\t\tD7129F942567FDFF0031D31B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tD71871E5245EE9AC001F1E4E /* RegExFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegExFetch.swift; sourceTree = \"<group>\"; };\n\t\tD71F8F0F246F8E5300A11283 /* ActivityViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityViewController.swift; sourceTree = \"<group>\"; };\n\t\tD721780A2451776000F17390 /* RegExTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegExTextView.swift; sourceTree = \"<group>\"; };\n\t\tD731F649245EF4C500EEE17F /* RegEx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegEx.swift; sourceTree = \"<group>\"; };\n\t\tD731F64D245EF77600EEE17F /* DataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = \"<group>\"; };\n\t\tD731F64F245F053A00EEE17F /* LibraryView+Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"LibraryView+Data.swift\"; sourceTree = \"<group>\"; };\n\t\tD731F651245F0B9A00EEE17F /* LibraryItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryItemView.swift; sourceTree = \"<group>\"; };\n\t\tD731F6552460F2BA00EEE17F /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = \"<group>\"; };\n\t\tD74BF66C247A3C0A0032EE35 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = \"<group>\"; };\n\t\tD75902AC2513C6300032013F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tD75902AF2513C6620032013F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = \"<group>\"; };\n\t\tD7732028245D1877003C0CF8 /* RegExSyntaxHighlighter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegExSyntaxHighlighter.swift; sourceTree = \"<group>\"; };\n\t\tD7732032245D3388003C0CF8 /* String+NSRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"String+NSRange.swift\"; sourceTree = \"<group>\"; };\n\t\tD7732034245D3456003C0CF8 /* MatchesTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchesTextView.swift; sourceTree = \"<group>\"; };\n\t\tD77C7971247EBC6D00D3B1B2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = en; path = en.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD77C7973247EBC7300D3B1B2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = \"zh-Hans\"; path = \"zh-Hans.lproj/CheatSheet.plist\"; sourceTree = \"<group>\"; };\n\t\tD78E45B82E47A2B0002ACA56 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = ja; path = ja.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45B92E47A2D2002ACA56 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = de; path = de.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45BA2E47A2DD002ACA56 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = es; path = es.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45BB2E483529002ACA56 /* ShortcutKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutKeys.swift; sourceTree = \"<group>\"; };\n\t\tD78E45BD2E47A2E8002ACA56 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = fr; path = fr.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45BE2E47A2F3002ACA56 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = it; path = it.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45BF2E47A300002ACA56 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = ko; path = ko.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45C02E47A310002ACA56 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = nl; path = nl.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD78E45C12E47A320002ACA56 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = pl; path = pl.lproj/CheatSheet.plist; sourceTree = \"<group>\"; };\n\t\tD7A925DB2B81057E0023E8EA /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = \"<group>\"; };\n\t\tD7BB73F8244F47E400343AC5 /* EditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorView.swift; sourceTree = \"<group>\"; };\n\t\tD7CCA7D1244E010D00D81C74 /* RegEx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RegEx.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tD7CCA7D8244E010D00D81C74 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = \"<group>\"; };\n\t\tD7CCA7DA244E010F00D81C74 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tD7CCA7DD244E010F00D81C74 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\tD7CCA7E2244E010F00D81C74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tD7CCA7E8244E011C00D81C74 /* RegEx+.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = \"RegEx+.entitlements\"; sourceTree = \"<group>\"; };\n\t\tD7CCA7EB244E038E00D81C74 /* LibraryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryView.swift; sourceTree = \"<group>\"; };\n\t\tD7CCA7EE244E041000D81C74 /* CheatSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatSheetView.swift; sourceTree = \"<group>\"; };\n\t\tD7D0E96F249F4FA800F6B9DF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = \"zh-Hant\"; path = \"zh-Hant.lproj/CheatSheet.plist\"; sourceTree = \"<group>\"; };\n\t\tD7DC51492529645F00A495E2 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = \"<group>\"; };\n\t\tD7E9174A246C47D400F2BE17 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };\n\t\tD7EF73592453E7FB005974F0 /* EditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorViewModel.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tD7CCA7CE244E010D00D81C74 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD709006C245DB72C00326016 /* CloudKit.framework in Frameworks */,\n\t\t\t\tD78E45502E4795E5002ACA56 /* AppAboutView in Frameworks */,\n\t\t\t\tD7F100012F100001002ACA56 /* _RegexParser in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tD709006A245DB72C00326016 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD709006B245DB72C00326016 /* CloudKit.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7090093245DC43800326016 /* CoreData+CloudKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD731F64D245EF77600EEE17F /* DataManager.swift */,\n\t\t\t\tD731F649245EF4C500EEE17F /* RegEx.swift */,\n\t\t\t\tD71871E5245EE9AC001F1E4E /* RegExFetch.swift */,\n\t\t\t);\n\t\t\tpath = \"CoreData+CloudKit\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7090094245DC46200326016 /* Editor */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7BB73F8244F47E400343AC5 /* EditorView.swift */,\n\t\t\t\tD7EF73592453E7FB005974F0 /* EditorViewModel.swift */,\n\t\t\t\t73E3E4B7BCD55ACE7E2C6A55 /* RegExFlowView.swift */,\n\t\t\t);\n\t\t\tpath = Editor;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD74BF66E247A3C0E0032EE35 /* About */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD74BF66C247A3C0A0032EE35 /* AboutView.swift */,\n\t\t\t);\n\t\t\tpath = About;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD761DDC5245DC4DF00FE0678 /* Library */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7CCA7EB244E038E00D81C74 /* LibraryView.swift */,\n\t\t\t\tD731F651245F0B9A00EEE17F /* LibraryItemView.swift */,\n\t\t\t\tD731F64F245F053A00EEE17F /* LibraryView+Data.swift */,\n\t\t\t);\n\t\t\tpath = Library;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD761DDC6245DC52A00FE0678 /* CheatSheet */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7CCA7EE244E041000D81C74 /* CheatSheetView.swift */,\n\t\t\t);\n\t\t\tpath = CheatSheet;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7732027245D185C003C0CF8 /* RegExTextView */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD78E45BB2E483529002ACA56 /* ShortcutKeys.swift */,\n\t\t\t\tD721780A2451776000F17390 /* RegExTextView.swift */,\n\t\t\t\tD7732028245D1877003C0CF8 /* RegExSyntaxHighlighter.swift */,\n\t\t\t\tD7732034245D3456003C0CF8 /* MatchesTextView.swift */,\n\t\t\t\tD7732032245D3388003C0CF8 /* String+NSRange.swift */,\n\t\t\t);\n\t\t\tpath = RegExTextView;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7CCA7C8244E010D00D81C74 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7CCA7D3244E010D00D81C74 /* RegEx+ */,\n\t\t\t\tD7CCA7D2244E010D00D81C74 /* Products */,\n\t\t\t\tD709006A245DB72C00326016 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7CCA7D2244E010D00D81C74 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7CCA7D1244E010D00D81C74 /* RegEx.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7CCA7D3244E010D00D81C74 /* RegEx+ */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7E9174A246C47D400F2BE17 /* README.md */,\n\t\t\t\tD7CCA7E8244E011C00D81C74 /* RegEx+.entitlements */,\n\t\t\t\tD75902AC2513C6300032013F /* AppDelegate.swift */,\n\t\t\t\tD75902AF2513C6620032013F /* SceneDelegate.swift */,\n\t\t\t\tD7CCA7D8244E010D00D81C74 /* HomeView.swift */,\n\t\t\t\tD7090093245DC43800326016 /* CoreData+CloudKit */,\n\t\t\t\tD761DDC5245DC4DF00FE0678 /* Library */,\n\t\t\t\tD7090094245DC46200326016 /* Editor */,\n\t\t\t\tD74BF66E247A3C0E0032EE35 /* About */,\n\t\t\t\tD761DDC6245DC52A00FE0678 /* CheatSheet */,\n\t\t\t\tD7CCA7ED244E039D00D81C74 /* Views */,\n\t\t\t\tD7CCA7DA244E010F00D81C74 /* Assets.xcassets */,\n\t\t\t\tD7CCA7DF244E010F00D81C74 /* LaunchScreen.storyboard */,\n\t\t\t\tD7CCA7E2244E010F00D81C74 /* Info.plist */,\n\t\t\t\tD7090090245DB87C00326016 /* RegEx.xcdatamodeld */,\n\t\t\t\tD7CCA7DC244E010F00D81C74 /* Preview Content */,\n\t\t\t\tD77C7972247EBC6D00D3B1B2 /* CheatSheet.plist */,\n\t\t\t\tD7A925DB2B81057E0023E8EA /* Localizable.xcstrings */,\n\t\t\t);\n\t\t\tpath = \"RegEx+\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7CCA7DC244E010F00D81C74 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7CCA7DD244E010F00D81C74 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7CCA7ED244E039D00D81C74 /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7732027245D185C003C0CF8 /* RegExTextView */,\n\t\t\t\tD731F6552460F2BA00EEE17F /* SafariView.swift */,\n\t\t\t\tD71F8F0F246F8E5300A11283 /* ActivityViewController.swift */,\n\t\t\t\tD7DC51492529645F00A495E2 /* SearchView.swift */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tD7CCA7D0244E010D00D81C74 /* RegEx+ */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = D7CCA7E5244E010F00D81C74 /* Build configuration list for PBXNativeTarget \"RegEx+\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tD734CBE224AA41E900C1F385 /* SwiftLint */,\n\t\t\t\tD7CCA7CD244E010D00D81C74 /* Sources */,\n\t\t\t\tD7CCA7CE244E010D00D81C74 /* Frameworks */,\n\t\t\t\tD7CCA7CF244E010D00D81C74 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"RegEx+\";\n\t\t\tpackageProductDependencies = (\n\t\t\t\tD78E454F2E4795E5002ACA56 /* AppAboutView */,\n\t\t\t\tD7F100032F100001002ACA56 /* _RegexParser */,\n\t\t\t);\n\t\t\tproductName = RegExPro;\n\t\t\tproductReference = D7CCA7D1244E010D00D81C74 /* RegEx.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tD7CCA7C9244E010D00D81C74 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastSwiftUpdateCheck = 1150;\n\t\t\t\tLastUpgradeCheck = 1640;\n\t\t\t\tORGANIZATIONNAME = Lex.sh;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tD7CCA7D0244E010D00D81C74 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.4.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = D7CCA7CC244E010D00D81C74 /* Build configuration list for PBXProject \"RegEx+\" */;\n\t\t\tcompatibilityVersion = \"Xcode 11.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\t\"zh-Hans\",\n\t\t\t\t\"zh-Hant\",\n\t\t\t\tBase,\n\t\t\t\tja,\n\t\t\t\tde,\n\t\t\t\tes,\n\t\t\t\tfr,\n\t\t\t\tit,\n\t\t\t\tko,\n\t\t\t\tnl,\n\t\t\t\tpl,\n\t\t\t);\n\t\t\tmainGroup = D7CCA7C8244E010D00D81C74;\n\t\t\tpackageReferences = (\n\t\t\t\tD78E454E2E4795E5002ACA56 /* XCRemoteSwiftPackageReference \"AppAboutView\" */,\n\t\t\t\tD7F100022F100001002ACA56 /* XCRemoteSwiftPackageReference \"swift-experimental-string-processing\" */,\n\t\t\t);\n\t\t\tproductRefGroup = D7CCA7D2244E010D00D81C74 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tD7CCA7D0244E010D00D81C74 /* RegEx+ */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tD7CCA7CF244E010D00D81C74 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD7CCA7E1244E010F00D81C74 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tD7A925DC2B81057E0023E8EA /* Localizable.xcstrings in Resources */,\n\t\t\t\tD77C7970247EBC6D00D3B1B2 /* CheatSheet.plist in Resources */,\n\t\t\t\tD7CCA7DE244E010F00D81C74 /* Preview Assets.xcassets in Resources */,\n\t\t\t\tD7CCA7DB244E010F00D81C74 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\tD734CBE224AA41E900C1F385 /* SwiftLint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = SwiftLint;\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"export PATH=/opt/homebrew/bin/:$PATH\\nif which swiftlint >/dev/null; then\\n  swiftlint\\nelse\\n  echo \\\"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\\\"\\nfi\\n\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tD7CCA7CD244E010D00D81C74 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD731F64B245EF4C500EEE17F /* RegEx.swift in Sources */,\n\t\t\t\tD7CCA7EC244E038E00D81C74 /* LibraryView.swift in Sources */,\n\t\t\t\tD7732035245D3456003C0CF8 /* MatchesTextView.swift in Sources */,\n\t\t\t\tD71871E6245EE9AC001F1E4E /* RegExFetch.swift in Sources */,\n\t\t\t\tD71F8F10246F8E5300A11283 /* ActivityViewController.swift in Sources */,\n\t\t\t\tD731F6562460F2BA00EEE17F /* SafariView.swift in Sources */,\n\t\t\t\tD7732033245D3388003C0CF8 /* String+NSRange.swift in Sources */,\n\t\t\t\tD75902B02513C6620032013F /* SceneDelegate.swift in Sources */,\n\t\t\t\tD7CCA7EF244E041000D81C74 /* CheatSheetView.swift in Sources */,\n\t\t\t\tD721780B2451776000F17390 /* RegExTextView.swift in Sources */,\n\t\t\t\tD7DC514A2529645F00A495E2 /* SearchView.swift in Sources */,\n\t\t\t\tD7090092245DB87C00326016 /* RegEx.xcdatamodeld in Sources */,\n\t\t\t\tD731F64E245EF77600EEE17F /* DataManager.swift in Sources */,\n\t\t\t\tD78E45BC2E48352B002ACA56 /* ShortcutKeys.swift in Sources */,\n\t\t\t\tD7EF735A2453E7FB005974F0 /* EditorViewModel.swift in Sources */,\n\t\t\t\tD731F652245F0B9A00EEE17F /* LibraryItemView.swift in Sources */,\n\t\t\t\tD7BB73F9244F47E400343AC5 /* EditorView.swift in Sources */,\n\t\t\t\tD74BF66D247A3C0A0032EE35 /* AboutView.swift in Sources */,\n\t\t\t\tD7732029245D1877003C0CF8 /* RegExSyntaxHighlighter.swift in Sources */,\n\t\t\t\tD75902AD2513C6300032013F /* AppDelegate.swift in Sources */,\n\t\t\t\tD731F650245F053A00EEE17F /* LibraryView+Data.swift in Sources */,\n\t\t\t\tD7CCA7D9244E010D00D81C74 /* HomeView.swift in Sources */,\n\t\t\t\t2B98B5427488929CF4B9104F /* RegExFlowView.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tD77C7972247EBC6D00D3B1B2 /* CheatSheet.plist */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tD77C7971247EBC6D00D3B1B2 /* en */,\n\t\t\t\tD77C7973247EBC7300D3B1B2 /* zh-Hans */,\n\t\t\t\tD7D0E96F249F4FA800F6B9DF /* zh-Hant */,\n\t\t\t\tD78E45B82E47A2B0002ACA56 /* ja */,\n\t\t\t\tD78E45B92E47A2D2002ACA56 /* de */,\n\t\t\t\tD78E45BA2E47A2DD002ACA56 /* es */,\n\t\t\t\tD78E45BD2E47A2E8002ACA56 /* fr */,\n\t\t\t\tD78E45BE2E47A2F3002ACA56 /* it */,\n\t\t\t\tD78E45BF2E47A300002ACA56 /* ko */,\n\t\t\t\tD78E45C02E47A310002ACA56 /* nl */,\n\t\t\t\tD78E45C12E47A320002ACA56 /* pl */,\n\t\t\t);\n\t\t\tname = CheatSheet.plist;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7CCA7DF244E010F00D81C74 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tD7129F942567FDFF0031D31B /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tD7CCA7E3244E010F00D81C74 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEVELOPMENT_TEAM = 5SKD83S59G;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = NO;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.6;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tD7CCA7E4244E010F00D81C74 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDEVELOPMENT_TEAM = 5SKD83S59G;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = NO;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.6;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tD7CCA7E6244E010F00D81C74 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"RegEx+/RegEx+.entitlements\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 22;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"RegEx+/Preview\\\\ Content/Preview\\\\ Assets.xcassets\";\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/RegEx+/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 0.9;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = sh.lex.RegExCatalyst;\n\t\t\t\tPRODUCT_MODULE_NAME = \"$(PRODUCT_NAME:c99extidentifier)App\";\n\t\t\t\tPRODUCT_NAME = RegEx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphoneos iphonesimulator\";\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tSUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;\n\t\t\t\tSUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tD7CCA7E7244E010F00D81C74 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"RegEx+/RegEx+.entitlements\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 22;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"RegEx+/Preview\\\\ Content/Preview\\\\ Assets.xcassets\";\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/RegEx+/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 0.9;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = sh.lex.RegExCatalyst;\n\t\t\t\tPRODUCT_MODULE_NAME = \"$(PRODUCT_NAME:c99extidentifier)App\";\n\t\t\t\tPRODUCT_NAME = RegEx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphoneos iphonesimulator\";\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tSUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;\n\t\t\t\tSUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tD7CCA7CC244E010D00D81C74 /* Build configuration list for PBXProject \"RegEx+\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tD7CCA7E3244E010F00D81C74 /* Debug */,\n\t\t\t\tD7CCA7E4244E010F00D81C74 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tD7CCA7E5244E010F00D81C74 /* Build configuration list for PBXNativeTarget \"RegEx+\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tD7CCA7E6244E010F00D81C74 /* Debug */,\n\t\t\t\tD7CCA7E7244E010F00D81C74 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\tD78E454E2E4795E5002ACA56 /* XCRemoteSwiftPackageReference \"AppAboutView\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lexrus/AppAboutView\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 0.0.4;\n\t\t\t};\n\t\t};\n\t\tD7F100022F100001002ACA56 /* XCRemoteSwiftPackageReference \"swift-experimental-string-processing\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/swiftlang/swift-experimental-string-processing\";\n\t\t\trequirement = {\n\t\t\t\tkind = revision;\n\t\t\t\trevision = e3f7b258f75a42b78624972131a0175cb0b662da;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\tD78E454F2E4795E5002ACA56 /* AppAboutView */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = D78E454E2E4795E5002ACA56 /* XCRemoteSwiftPackageReference \"AppAboutView\" */;\n\t\t\tproductName = AppAboutView;\n\t\t};\n\t\tD7F100032F100001002ACA56 /* _RegexParser */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = D7F100022F100001002ACA56 /* XCRemoteSwiftPackageReference \"swift-experimental-string-processing\" */;\n\t\t\tproductName = _RegexParser;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\n/* Begin XCVersionGroup section */\n\t\tD7090090245DB87C00326016 /* RegEx.xcdatamodeld */ = {\n\t\t\tisa = XCVersionGroup;\n\t\t\tchildren = (\n\t\t\t\tD7090091245DB87C00326016 /* RegEx.xcdatamodel */,\n\t\t\t);\n\t\t\tcurrentVersion = D7090091245DB87C00326016 /* RegEx.xcdatamodel */;\n\t\t\tpath = RegEx.xcdatamodeld;\n\t\t\tsourceTree = \"<group>\";\n\t\t\tversionGroupType = wrapper.xcdatamodel;\n\t\t};\n/* End XCVersionGroup section */\n\t};\n\trootObject = D7CCA7C9244E010D00D81C74 /* Project object */;\n}\n"
  },
  {
    "path": "fastlane/Deliverfile",
    "content": "# The Deliverfile allows you to store various App Store Connect metadata\n# For more information, check out the docs\n# https://docs.fastlane.tools/actions/deliver/\n"
  },
  {
    "path": "fastlane/Fastfile",
    "content": "# This file contains the fastlane.tools configuration\n# You can find the documentation at https://docs.fastlane.tools\n#\n# For a list of all available actions, check out\n#\n#     https://docs.fastlane.tools/actions\n#\n# For a list of all available plugins, check out\n#\n#     https://docs.fastlane.tools/plugins/available-plugins\n#\n\n# Uncomment the line if you want fastlane to automatically update itself\n# update_fastlane\n\ndefault_platform(:ios)\n\nplatform :ios do\n  desc \"Push a new release build to the App Store\"\n  lane :release do\n    increment_build_number(xcodeproj: \"RegEx+.xcodeproj\")\n    build_app(scheme: \"RegEx+\")\n    upload_to_app_store\n  end\nend\n"
  },
  {
    "path": "fastlane/metadata/copyright.txt",
    "content": "2025 Lex.sh\n"
  },
  {
    "path": "fastlane/metadata/de-DE/apple_tv_privacy_policy.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/de-DE/description.txt",
    "content": "Entfesseln Sie die Macht der regulären Ausdrücke mit RegEx+!\n\nVon Entwicklern für Entwickler konzipiert, ist RegEx+ Ihr unverzichtbares Werkzeug zur Beherrschung regulärer Ausdrücke auf macOS und iOS. Tauchen Sie ein in eine nahtlose Erfahrung, bei der Ihre Daten mühelos über CloudKit zwischen Geräten synchronisiert werden, sodass Sie Ihre Arbeit haben, wo und wann Sie sie brauchen. Ob Anfänger oder erfahrener Profi, unser umfassendes Cheatsheet entmystifiziert Metazeichen und Operatoren und befähigt Sie, komplexe Muster mühelos zu entschlüsseln und zu konstruieren. Verbessern Sie Ihr Coding-Spiel mit RegEx+ und transformieren Sie die Art, wie Sie mit Text, Daten und mehr umgehen!\n"
  },
  {
    "path": "fastlane/metadata/de-DE/keywords.txt",
    "content": "regexp,reguläre,ausdrücke,entwickler,programmieren,code,editor,pattern,syntax,ios,mac,software,tool"
  },
  {
    "path": "fastlane/metadata/de-DE/marketing_url.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/de-DE/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/de-DE/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/\n"
  },
  {
    "path": "fastlane/metadata/de-DE/promotional_text.txt",
    "content": "Teste, debugge und speichere Regex-Muster schneller auf iPhone, iPad und Mac. Live-Matching, Spickzettel und CloudKit-Synchronisation in einem fokussierten Tool.\n"
  },
  {
    "path": "fastlane/metadata/de-DE/release_notes.txt",
    "content": "Neues in RegEx+:\n\n• Unterstützung für Französisch, Italienisch, Koreanisch, Niederländisch und Polnisch hinzugefügt.\n• Leistungsoptimierungen und Stabilitätsverbesserungen.\n"
  },
  {
    "path": "fastlane/metadata/de-DE/subtitle.txt",
    "content": "Regex Spickzettel & Cloud-Sync"
  },
  {
    "path": "fastlane/metadata/de-DE/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/en-US/apple_tv_privacy_policy.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/en-US/description.txt",
    "content": "Unleash the Power of Regular Expressions with RegEx+!\n\nDesigned for developers by developers, RegEx+ is your go-to tool for mastering regular expressions on both macOS and iOS. Dive into a seamless experience as your data syncs effortlessly across devices via CloudKit, ensuring you have your work where you need it, when you need it. Whether you're a beginner or a seasoned pro, our comprehensive cheatsheet demystifies metacharacters and operators, empowering you to decode and construct complex patterns with ease. Elevate your coding game with RegEx+ and transform the way you handle text, data, and beyond!\n"
  },
  {
    "path": "fastlane/metadata/en-US/keywords.txt",
    "content": "regexp,tester,builder,match,replace,capture,group,validator,pattern,swift,nsregularexpression,editor\n"
  },
  {
    "path": "fastlane/metadata/en-US/marketing_url.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/en-US/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/en-US/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/\n"
  },
  {
    "path": "fastlane/metadata/en-US/promotional_text.txt",
    "content": "Test, debug, and save regex patterns faster on iPhone, iPad, and Mac. Live matching, cheat sheet, and CloudKit sync in one focused tool.\n"
  },
  {
    "path": "fastlane/metadata/en-US/release_notes.txt",
    "content": "What's New in RegEx+:\n\n• Added French, Italian, Korean, Dutch and Polish language support.\n• Performance optimizations and stability improvements.\n"
  },
  {
    "path": "fastlane/metadata/en-US/subtitle.txt",
    "content": "Regex Cheat Sheet + Cloud Sync\n"
  },
  {
    "path": "fastlane/metadata/en-US/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/es-ES/apple_tv_privacy_policy.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/es-ES/description.txt",
    "content": "¡Libera el Poder de las Expresiones Regulares con RegEx+!\n\nDiseñado por desarrolladores para desarrolladores, RegEx+ es tu herramienta esencial para dominar las expresiones regulares en macOS e iOS. Sumérgete en una experiencia perfecta mientras tus datos se sincronizan sin esfuerzo entre dispositivos a través de CloudKit, asegurando que tengas tu trabajo donde lo necesites, cuando lo necesites. Ya seas principiante o un profesional experimentado, nuestra hoja de referencia integral desmitifica metacaracteres y operadores, permitiéndote decodificar y construir patrones complejos con facilidad. ¡Eleva tu juego de programación con RegEx+ y transforma la forma en que manejas texto, datos y más!\n"
  },
  {
    "path": "fastlane/metadata/es-ES/keywords.txt",
    "content": "regexp,expresiones,regulares,programador,código,editor,patrón,sintaxis,ios,mac,software,herramienta"
  },
  {
    "path": "fastlane/metadata/es-ES/marketing_url.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/es-ES/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/es-ES/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/\n"
  },
  {
    "path": "fastlane/metadata/es-ES/promotional_text.txt",
    "content": "Pruebe, depure y guarde patrones regex más rápido en iPhone, iPad y Mac. Coincidencias en vivo, guía de consulta y sincronización CloudKit."
  },
  {
    "path": "fastlane/metadata/es-ES/release_notes.txt",
    "content": "Novedades en RegEx+:\n\n• Se ha añadido compatibilidad con los idiomas francés, italiano, coreano, neerlandés y polaco.\n• Optimizaciones de rendimiento y mejoras de estabilidad.\n"
  },
  {
    "path": "fastlane/metadata/es-ES/subtitle.txt",
    "content": "Acordeón Regex y Cloud Sync"
  },
  {
    "path": "fastlane/metadata/es-ES/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/fr-FR/apple_tv_privacy_policy.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/fr-FR/description.txt",
    "content": "Libérez la puissance des expressions régulières avec RegEx+ !\n\nConçu pour les développeurs par des développeurs, RegEx+ est votre outil de référence pour maîtriser les expressions régulières sur macOS et iOS. Plongez dans une expérience fluide où vos données se synchronisent automatiquement sur tous vos appareils via CloudKit, vous assurant d'avoir votre travail où vous en avez besoin, quand vous en avez besoin. Que vous soyez débutant ou professionnel chevronné, notre antisèche complète démystifie les métacaractères et les opérateurs, vous permettant de décoder et de construire des motifs complexes avec facilité. Élevez votre niveau de programmation avec RegEx+ et transformez votre façon de gérer le texte, les données et bien plus encore !\n"
  },
  {
    "path": "fastlane/metadata/fr-FR/keywords.txt",
    "content": "regexp,expression,régulière,développeur,code,éditeur,motif,syntaxe,ios,mac,logiciel,outil"
  },
  {
    "path": "fastlane/metadata/fr-FR/marketing_url.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/fr-FR/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/fr-FR/privacy_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/fr-FR/promotional_text.txt",
    "content": "Testez, déboguez et enregistrez vos regex plus vite sur iPhone, iPad et Mac. Matching en direct, antisèche et synchro CloudKit."
  },
  {
    "path": "fastlane/metadata/fr-FR/release_notes.txt",
    "content": "Quoi de neuf dans RegEx+ :\n\n• Ajout de la prise en charge des langues française, italienne, coréenne, néerlandaise et polonaise.\n• Optimisations des performances et améliorations de la stabilité.\n"
  },
  {
    "path": "fastlane/metadata/fr-FR/subtitle.txt",
    "content": "Antisèche Regex et Cloud Sync"
  },
  {
    "path": "fastlane/metadata/fr-FR/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/it/apple_tv_privacy_policy.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/it/description.txt",
    "content": "Scatena la potenza delle espressioni regolari con RegEx+!\n\nProgettato per sviluppatori da sviluppatori, RegEx+ è il tuo strumento di riferimento per padroneggiare le espressioni regolari su macOS e iOS. Immergiti in un'esperienza fluida dove i tuoi dati si sincronizzano automaticamente su tutti i dispositivi tramite CloudKit, assicurandoti di avere il tuo lavoro dove ne hai bisogno, quando ne hai bisogno. Che tu sia un principiante o un professionista esperto, la nostra guida di riferimento completa demistifica metacaratteri e operatori, permettendoti di decodificare e costruire pattern complessi con facilità. Eleva il tuo livello di programmazione con RegEx+ e trasforma il modo in cui gestisci testo, dati e molto altro!\n"
  },
  {
    "path": "fastlane/metadata/it/keywords.txt",
    "content": "regexp,espressione,regolare,sviluppatore,codice,editor,pattern,sintassi,ios,mac,software,strumento"
  },
  {
    "path": "fastlane/metadata/it/marketing_url.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/it/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/it/privacy_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/it/promotional_text.txt",
    "content": "Testa, debugga e salva i pattern regex più velocemente su iPhone, iPad e Mac. Matching in tempo reale, guida rapida e sincro CloudKit."
  },
  {
    "path": "fastlane/metadata/it/release_notes.txt",
    "content": "Novità in RegEx+:\n\n• Aggiunto il supporto per le lingue francese, italiana, coreana, olandese e polacca.\n• Ottimizzazioni delle prestazioni e miglioramenti della stabilità.\n"
  },
  {
    "path": "fastlane/metadata/it/subtitle.txt",
    "content": "Guida Regex e Cloud Sync"
  },
  {
    "path": "fastlane/metadata/it/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/ja/apple_tv_privacy_policy.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/ja/description.txt",
    "content": "RegEx+で正規表現の力を解き放とう！\n\n開発者による開発者のためのRegEx+は、macOSとiOSで正規表現をマスターするための必須ツールです。CloudKitを通じてデバイス間でデータが簡単に同期されるシームレスな体験に飛び込み、必要な時に必要な場所で作業ができることを保証します。初心者でも熟練のプロでも、包括的なチートシートがメタ文字と演算子を分かりやすく説明し、複雑なパターンを簡単にデコードして構築できるようにします。RegEx+でコーディングスキルを向上させ、テキスト、データなどの扱い方を変革しましょう！\n"
  },
  {
    "path": "fastlane/metadata/ja/keywords.txt",
    "content": "正規表現,開発者,プログラミング,コード,エディタ,パターン,構文,ソフトウェア,ツール,ios,mac,regexp"
  },
  {
    "path": "fastlane/metadata/ja/marketing_url.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/ja/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/ja/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/\n"
  },
  {
    "path": "fastlane/metadata/ja/promotional_text.txt",
    "content": "iPhone、iPad、Macで正規表現のテストと保存を高速化。ライブマッチング、リファレンス、CloudKit同期を一つのツールで。"
  },
  {
    "path": "fastlane/metadata/ja/release_notes.txt",
    "content": "RegEx+ の新機能:\n\n• フランス語、イタリア語、韓国語、オランダ語、ポーランド語のサポートを追加しました。\n• パフォーマンスの最適化と安定性の向上。\n"
  },
  {
    "path": "fastlane/metadata/ja/subtitle.txt",
    "content": "正規表現の早見表とクラウド同期"
  },
  {
    "path": "fastlane/metadata/ja/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/nl-NL/apple_tv_privacy_policy.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/nl-NL/description.txt",
    "content": "Ontketen de kracht van Reguliere Expressies met RegEx+!\n\nRegEx+ is ontworpen door ontwikkelaars voor ontwikkelaars en is dé tool voor het beheersen van reguliere expressies op zowel macOS als iOS. Ervaar een naadloze ervaring terwijl je gegevens moeiteloos worden gesynchroniseerd tussen apparaten via CloudKit, zodat je je werk altijd bij de hand hebt. Of je nu een beginner bent of een ervaren pro, ons uitgebreide spiekbriefje verheldert metatekens en operatoren, waardoor je complexe patronen met gemak kunt ontcijferen en construeren. Til je programmeervaardigheden naar een hoger niveau met RegEx+ en transformeer de manier waarop je tekst, gegevens en meer verwerkt!"
  },
  {
    "path": "fastlane/metadata/nl-NL/keywords.txt",
    "content": "regexp,reguliere,expressies,ontwikkelaar,code,editor,patroon,syntax,ios,mac,software,tool"
  },
  {
    "path": "fastlane/metadata/nl-NL/marketing_url.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/nl-NL/name.txt",
    "content": "RegEx+"
  },
  {
    "path": "fastlane/metadata/nl-NL/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/"
  },
  {
    "path": "fastlane/metadata/nl-NL/promotional_text.txt",
    "content": "Test, debug en bewaar regex-patronen sneller op iPhone, iPad en Mac. Live matching, spiekbriefje en CloudKit-synchronisatie."
  },
  {
    "path": "fastlane/metadata/nl-NL/release_notes.txt",
    "content": "Wat is er nieuw in RegEx+:\n\n• Ondersteuning voor de Franse, Italiaanse, Koreaanse, Nederlandse en Poolse taal toegevoegd.\n• Prestatieoptimalisaties en stabiliteitsverbeteringen.\n"
  },
  {
    "path": "fastlane/metadata/nl-NL/subtitle.txt",
    "content": "Regex Spiekbrief & Cloud Sync"
  },
  {
    "path": "fastlane/metadata/nl-NL/support_url.txt",
    "content": "https://x.com/lexrus"
  },
  {
    "path": "fastlane/metadata/pl/apple_tv_privacy_policy.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/pl/description.txt",
    "content": "Uwolnij moc Wyrażeń Regularnych z RegEx+!\n\nZaprojektowany przez programistów dla programistów, RegEx+ to Twoje podstawowe narzędzie do opanowania wyrażeń regularnych na macOS i iOS. Ciesz się płynną pracą, gdy Twoje dane synchronizują się bez wysiłku między urządzeniami przez CloudKit, zapewniając dostęp do pracy zawsze wtedy, gdy jej potrzebujesz. Niezależnie od tego, czy jesteś początkującym, czy doświadczonym profesjonalistą, nasza kompleksowa ściąga wyjaśnia znaki specjalne i operatory, pozwalając z łatwością dekodować i budować złożone wzorce. Podnieś swoje umiejętności kodowania dzięki RegEx+ i odmień sposób, w jaki pracujesz z tekstem, danymi i nie tylko!"
  },
  {
    "path": "fastlane/metadata/pl/keywords.txt",
    "content": "regexp,wyrażenia,regularne,programista,kod,edytor,wzór,składnia,ios,mac,oprogramowanie,narzędzie"
  },
  {
    "path": "fastlane/metadata/pl/marketing_url.txt",
    "content": ""
  },
  {
    "path": "fastlane/metadata/pl/name.txt",
    "content": "RegEx+"
  },
  {
    "path": "fastlane/metadata/pl/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/"
  },
  {
    "path": "fastlane/metadata/pl/promotional_text.txt",
    "content": "Testuj, debuguj i zapisuj wyrażenia regex szybciej na iPhone, iPad i Mac. Dopasowanie na żywo, ściąga i synchronizacja CloudKit."
  },
  {
    "path": "fastlane/metadata/pl/release_notes.txt",
    "content": "Co nowego w RegEx+:\n\n• Dodano obsługę języka francuskiego, włoskiego, koreańskiego, holenderskiego i polskiego.\n• Optymalizacja wydajności i poprawa stabilności.\n"
  },
  {
    "path": "fastlane/metadata/pl/subtitle.txt",
    "content": "Ściąga Regex i Cloud Sync"
  },
  {
    "path": "fastlane/metadata/pl/support_url.txt",
    "content": "https://x.com/lexrus"
  },
  {
    "path": "fastlane/metadata/primary_category.txt",
    "content": "DEVELOPER_TOOLS\n"
  },
  {
    "path": "fastlane/metadata/primary_first_sub_category.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/primary_second_sub_category.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/secondary_category.txt",
    "content": "UTILITIES\n"
  },
  {
    "path": "fastlane/metadata/secondary_first_sub_category.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/secondary_second_sub_category.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/apple_tv_privacy_policy.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/description.txt",
    "content": "用 RegEx+ 释放正则表达式的力量！\n\n由开发者为开发者设计，RegEx+ 是您在 macOS 和 iOS 上掌握正则表达式的必备工具。沉浸在无缝体验中，您的数据通过 CloudKit 在设备间轻松同步，确保您在需要的时候、需要的地方都能访问您的工作。无论您是初学者还是经验丰富的专业人士，我们全面的速查表都能揭开元字符和操作符的神秘面纱，让您轻松解码和构建复杂模式。用 RegEx+ 提升您的编程技能，改变您处理文本、数据等内容的方式！\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/keywords.txt",
    "content": "正则表达式,正则,开发,编程,代码,编辑器,模式,语法,软件,工具,ios,mac,regexp"
  },
  {
    "path": "fastlane/metadata/zh-Hans/marketing_url.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/promotional_text.txt",
    "content": "在 iPhone、iPad 和 Mac 上更快速地测试、调试和保存正则表达式。实时匹配、速查表和 CloudKit 同步，一站式搞定。"
  },
  {
    "path": "fastlane/metadata/zh-Hans/release_notes.txt",
    "content": "RegEx+ 新功能：\n\n• 新增法语、意大利语、韩语、荷兰语和波兰语支持。\n• 性能优化和稳定性改进。\n"
  },
  {
    "path": "fastlane/metadata/zh-Hans/subtitle.txt",
    "content": "正则表达式速查表与云同步"
  },
  {
    "path": "fastlane/metadata/zh-Hans/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/apple_tv_privacy_policy.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/description.txt",
    "content": "用 RegEx+ 釋放正則表達式的力量！\n\n由開發者為開發者設計，RegEx+ 是您在 macOS 和 iOS 上掌握正則表達式的必備工具。沉浸在無縫體驗中，您的資料透過 CloudKit 在裝置間輕鬆同步，確保您在需要的時候、需要的地方都能存取您的工作。無論您是初學者還是經驗豐富的專業人士，我們全面的速查表都能揭開元字符和操作符的神秘面紗，讓您輕鬆解碼和構建複雜模式。用 RegEx+ 提升您的程式設計技能，改變您處理文字、資料等內容的方式！\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/keywords.txt",
    "content": "正則表達式,正則,開發,編程,代碼,編輯器,模式,語法,軟件,工具,ios,mac,regexp"
  },
  {
    "path": "fastlane/metadata/zh-Hant/marketing_url.txt",
    "content": "\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/name.txt",
    "content": "RegEx+\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/privacy_url.txt",
    "content": "https://lex.sh/regexplus/privacypolicy/\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/promotional_text.txt",
    "content": "在 iPhone、iPad 和 Mac 上更快速地測試、調試和保存正則表達式。即時匹配、速查表和 CloudKit 同步，一站式搞定。"
  },
  {
    "path": "fastlane/metadata/zh-Hant/release_notes.txt",
    "content": "RegEx+ 新功能：\n\n• 新增法語、義大利語、韓語、荷蘭語和波蘭語支援。\n• 效能優化和穩定性改進。\n"
  },
  {
    "path": "fastlane/metadata/zh-Hant/subtitle.txt",
    "content": "正則表達式速查表與雲同步"
  },
  {
    "path": "fastlane/metadata/zh-Hant/support_url.txt",
    "content": "https://x.com/lexrus\n"
  },
  {
    "path": "mise.toml",
    "content": "[tasks.sc2tc]\ndescription = \"Convert Simplified Chinese to Traditional Chinese using OpenCC\"\nrun = \"opencc -c s2hk -i RegEx+/zh-Hans.lproj/CheatSheet.plist -o RegEx+/zh-Hant.lproj/CheatSheet.plist\"\n\n[tasks.pull-metadata]\ndescription = \"Pull all metadata from App Store for all platforms\"\nrun = [\n  \"fastlane deliver download_metadata -j ios --api_key_path fastlane/keys/app_key.json --sync_screenshots --force\",\n  \"fastlane deliver download_metadata -j osx --api_key_path fastlane/keys/app_key.json --sync_screenshots --force\",\n]\n\n[tasks.push-metadata]\ndescription = \"Push all metadata to App Store for all platforms\"\nrun = [\n  \"fastlane deliver upload_metadata -j ios --api_key_path fastlane/keys/app_key.json --sync_screenshots --force\",\n  \"fastlane deliver upload_metadata -j osx --api_key_path fastlane/keys/app_key.json --sync_screenshots --force\",\n]\n\n"
  }
]