はじめに
たまに正規表現を使って色々したくなるときがありますがその都度検索してたので正規表現についてまとめました。
アプリ内で使ったことはあまりないですがターミナルとかスクリプト、ちょっとしたツール作成時に正規表現のお世話になることがあります。使えると色々便利です!!
よく使う表現
全部まとめると大変なのでよく使うもののみです。
表現 | 説明 | 表現の例 | マッチする文字列の例 |
---|---|---|---|
. | 任意の一文字 | . | あ |
^ | 先頭 | ^あ | あいうえお |
\$ | 行末 | お\$ | あいうえお |
+ | 直前文字の 0 回以上の繰り返し | o+ | F! Fo! Fooooo! |
* | 直前文字の 1 回以上の繰り返し | o* | Fo! Fooooo! |
? | 直前文字が 0 個 or 1 個 | o? | F! Fo! |
() | 塊 | (hoge)* | hoge hogehoge |
| | OR | (iOS|iPadOS) | iOS 14 iPadOS 14 |
[] | OR | [abc] | a b c |
[^] | 否定 | [^abc] | e f (a, b, c以外の文字) |
半角数字
[0-9]
半角アルファベット
[a-z]
日本語(たぶん文字コードによってちょっと違う。。。)
[ぁ-んァ-ヶ亜-熙]
利用例
Swift
あんま使わないけど Swift
でやるとしたらこんな感じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
extension String { func isMatch(_ pattern: String) -> Bool { guard let regex = try? NSRegularExpression(pattern: pattern) else { return false } let matches = regex.matches(in: self, range: NSRange(location: 0, length: count)) return matches.count > 0 } } func testMatches() { let pattern = "^(iOS|iPadOS) [0-9]+\\.[0-9]$" // マッチする XCTAssert("iOS 13.4".isMatch(pattern)) XCTAssert("iPadOS 13.2".isMatch(pattern)) // マッチしない XCTAssert("iPad 13.2".isMatch(pattern)) XCTAssert("iOS 13.4です".isMatch(pattern)) XCTAssert("OSはiOS 13.4".isMatch(pattern)) } |
Ruby
Rubyだと gsub
で置換ができる
1 |
p "iOS 13.4".gsub(/[0-9]+\.[0-9]$/, "14.0") # iOS14.0 |
ターミナル
ターミナルのファイル検索とかファイル名一括変更のときにたまにお世話になることも。。。
1 |
find -E . -type f -iregex ".*\.(png|jpg|jpeg)" |
結果
1 2 3 4 5 6 7 8 9 |
./テスト2/testView4_画面4_iPhone_13_5_414x896.jpeg ./テスト2/testView2_画面2_iPhone_13_5_414x896.png ./テスト2/testView_画面1_iPhone_13_5_414x896.png ./テスト2/testView6_画面6_iPhone_13_5_414x896.png ./テスト2/testView5_画面5_iPhone_13_5_414x896.png ./テスト2/testView3_画面3_iPhone_13_5_414x896.png ./テスト1/testView_画面A_iPhone_13_5_414x896.png ./テスト1/testView2_画面B_iPhone_13_5_414x896.jpg ./テスト1/testView3_画面C_iPhone_13_5_414x896.png |
sedと組み合わせて一括リネームもできる
1 |
find -E . -type f -iregex ".*\.(png|jpg|jpeg)" | sed -e 'p;s/\_13_5_/_14_0_/' | xargs -n2 m |
結果
1 2 3 4 5 6 7 8 9 |
./テスト2/testView2_画面2_iPhone_14_0_414x896.png ./テスト2/testView_画面1_iPhone_14_0_414x896.png ./テスト2/testView6_画面6_iPhone_14_0_414x896.png ./テスト2/testView3_画面3_iPhone_14_0_414x896.png ./テスト2/testView5_画面5_iPhone_14_0_414x896.png ./テスト2/testView4_画面4_iPhone_14_0_414x896.jpeg ./テスト1/testView_画面A_iPhone_14_0_414x896.png ./テスト1/testView2_画面B_iPhone_14_0_414x896.jpg ./テスト1/testView3_画面C_iPhone_14_0_414x896.png |
おまけ
さいきんは簡単に Mac で動かせるアプリが作れるようになったのでファイル読み込んでその中の文字列を正規表現でチェックとかも Swift でちゃちゃっとできちゃいます。
下記は xib とかの strings ファイルを読み込んで文字検索をできるアプリです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
import UIKit struct StringData { let key: String let value: String } final class StringDataTableViewCell: UITableViewCell { @IBOutlet private weak var keyLabel: UILabel! @IBOutlet private weak var valueLabel: UILabel! func configure(_ config: StringData) { keyLabel.text = "key: \(config.key)" valueLabel.text = "value: \(config.value)" } } final class ViewController: UIViewController { @IBOutlet private weak var tableView: UITableView! { didSet { tableView.dataSource = self } } @IBOutlet private weak var searchBar: UISearchBar! { didSet { searchBar.delegate = self } } @IBOutlet private weak var importFileLabel: UILabel! var tableDataList = [StringData]() var originalDataList = [StringData]() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. importFileLabel.text = "選択ファイルなし" } @IBAction private func importFile(_ sender: Any) { #if targetEnvironment(macCatalyst) let picker = UIDocumentPickerViewController(documentTypes: ["strings"], in: .open) picker.delegate = self present(picker, animated: true) #endif } private func loadStringFile(at url: URL) { guard let str = try? String(contentsOf: url) else { return } let datas = str.components(separatedBy: "\n").filter { $0.isMatch("^\".+\" = \".+\";$") } originalDataList = datas.map { let values = $0.components(separatedBy: " = ") let key = values[0] let value = values[1] return StringData(key: key[1...key.count-2], value: value[1...value.count-3]) } searchBar.text = "" tableDataList = originalDataList tableView.reloadData() } } extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return tableDataList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! StringDataTableViewCell cell.configure(tableDataList[indexPath.row]) return cell } } extension ViewController: UISearchBarDelegate { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { let text = searchBar.text! tableDataList = originalDataList.filter { $0.key.contains(text) || $0.value.contains(text)} tableView.reloadData() } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" tableDataList = originalDataList tableView.reloadData() } } extension ViewController: UIDocumentPickerDelegate { func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { let url = urls.first! importFileLabel.text = url.absoluteString.components(separatedBy: "/").last loadStringFile(at: url) } } extension String { func isMatch(_ pattern: String) -> Bool { guard let regex = try? NSRegularExpression(pattern: pattern) else { return false } let matches = regex.matches(in: self, range: NSRange(location: 0, length: count)) return matches.count > 0 } } extension String { func index(at position: Int) -> String.Index { return index((position.signum() >= 0 ? startIndex : endIndex), offsetBy: position) } subscript (bounds: CountableClosedRange<Int>) -> String { let start = index(at: bounds.lowerBound) let end = index(at: bounds.upperBound) return String(self[start...end]) } } |
こんな感じ
他言語でスクリプトが書けなくても Swift が書ければ色々できます!!
おわりに
アプリで正規表現をがっつり使うことはあまりないけどツールとかではわりと便利なのでちょっとだけ使えるようにしておくと捗る。
コメント