Создание шаблонов для использования NSRegularExpression - PullRequest
0 голосов
/ 10 января 2019

Swift 4.4

Я хочу создать NSAttributedString, используя NSRegularExpression

~This two~ are *bold text* and different <textcolor> and ~strikethrough~ and _italic (word*)_ ~abc~

Похоже на это, enter image description here

Я могу создавать и назначать атрибуты, но проблема в том, что я не знаю, как использовать NSRegularExpression, но я попробовал много логики с помощью статьи rayenderlich .

Некоторые логики, которые я до сих пор пробовал.

(1) "(^|\\s|\\b)*(\\S).*(\\S)*($|\\s|\\b)"
(2) "(\\~(.*?)\\~)"
(3) "\\sand\\b"
(4) "(?:^|\\s|$)#[\\p{L}0-9_]*"
(5) "(?:^\\s+)|(?:\\s+$)"

Мне нужен всего один шаблон bold или italic или strikethrough

UPDATE

Дело 1:

let string = "~This two~ are *bold text* and different <textcolor> and ~strikethrough~ and _italic (word*)_ ~abc~"
let pattern = "((^|)~(.*?)(\\S+)~($|\\s))"

Выход ниже,

Pattern: ((^|)~(.*?)(\S+)~($|\s))
~This two~ 
~strikethrough~ 
~abc~

Дело 2:

let string = "~This two~ are *bold text* and different <textcolor> and ~strikethrough~ and _italic (word*)_ ~abc~"
let pattern = "((^|)~(.?)(\\S+)~($|\\s))" //here '*' removed

Выход ниже,

Pattern: ((^|)~(.?)(\S+)~($|\s))
~strikethrough~ 
~abc~

Заранее спасибо.
ОБНОВЛЕНИЕ 2
я нашел ответ,

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Этот код должен работать:

let string = "~This two~ are *bold text* and different <textcolor> and ~strikethrough~ and _italic (word*)_ ~abc~"

let embedded = ".*?"

let strikeThroughGroupName = "strikethroughGroupName"
let boldGroupName = "boldGroupName"
let colorGroupName = "colorGroupName"
let italicGroupName = "italicGroupName"
let groupNames = [strikeThroughGroupName, boldGroupName, italicGroupName, colorGroupName]

let pattern = "(~(?<\(strikeThroughGroupName)>\(embedded))~)|(<(?<\(colorGroupName)>\(embedded))>)|(_(?<\(italicGroupName)>\(embedded))_)|(\\*(?<\(boldGroupName)>\(embedded))\\*)"

print("Pattern: \(pattern)")

do {
    let regex = try NSRegularExpression(pattern: pattern, options: [])
    let matches = regex.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
    matches.forEach { (aMatch) in

        if let groupFound = groupNames.first(where: { aMatch.range(withName: $0).location != NSNotFound }),
            let range = Range(aMatch.range(withName: groupFound), in: string) {
            let textFound = string[range]
            print("Found: \(textFound) with effect: \(groupFound) at NSRange: \(aMatch.range(withName: groupFound))")
        }
        let fullNSRange = aMatch.range
        if let fullRange = Range(fullNSRange, in: string) {
            let textFound = string[fullRange]
            print("Full Text Found: \(textFound)")
        }
    }
} catch {
    print("Regex error: \(error)")
}

Выход:

$>Pattern: (~(?<strikethroughGroupName>.*?)~)|(<(?<colorGroupName>.*?)>)|(_(?<italicGroupName>.*?)_)|(\*(?<boldGroupName>.*?)\*)
$>Found: This two with effect: strikethroughGroupName at NSRange: {1, 8}
$>Full Text Found: ~This two~
$>Found: bold text with effect: boldGroupName at NSRange: {16, 9}
$>Full Text Found: *bold text*
$>Found: strikethrough with effect: strikethroughGroupName at NSRange: {59, 13}
$>Full Text Found: ~strikethrough~
$>Found: italic (word*) with effect: italicGroupName at NSRange: {79, 14}
$>Full Text Found: _italic (word*)_
$>Found: abc with effect: strikethroughGroupName at NSRange: {96, 3}
$>Full Text Found: ~abc~

Примечание стороны:
• Я использовал групповое именование (которое можно использовать в регулярных выражениях).
Это конструкции (?<groupName>groupToCapture).
• Я использовал embedded как таковой для быстрого тестирования. Это может не охватывать все случаи. Например, это не покрывает случай, когда есть изменение строки в string. Если это <text\ncolor> (есть линия разрыва), это не будет соответствовать. Там, при необходимости, вы можете использовать регулярное выражение, в которое хотите включить разрывы.

0 голосов
/ 12 января 2019

Я нашел ответ на свой вопрос, я объясню его на примере, чтобы вы могли попробовать сами.

вот оно,

    //Some randome bunch of words
let string = "1. *うちに* comes from the ~kanji~ *内* which mean “inside” or “within” and has _two distinct_ meanings in Japanese. 2. Firstly, it shows that something happens within ~a~ period of time. “While” something is happening, you do an action.~Very minimal as~ far as features tha *t* are supported in the Web version. It works in a pinch, if you’re in a hurry and ne. Nice~"

//to find words which are suppose to be stricked using '~' character
let pattern = "~[^\\s](.*?[^\\s])??~"

let regex = try! NSRegularExpression(pattern: pattern, options: [])
let matches = regex.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
matches.forEach { (aMatch) in
    let matchedRange = aMatch.range(at: 0)
    let matchingText = (string as NSString).substring(with: matchedRange)
    print(matchingText)
}


Большое «Большое спасибо»

, (1) ларм (2) Йоаким Даниэльсон (3) Поезд кодирования
0 голосов
/ 10 января 2019

Я не мог объединить шаблоны в один с или (|) и заставить их соответствовать должным образом, но если я сопоставил их один за другим, это работает

let string = "~This two~ are *bold text* and different <textcolor> and ~strikethrough~ and _italic (word*)_ ~abc~"
let textPattern = "[:alpha:][:punct:][:space:]"
let range = NSRange(location: 0, length: string.utf16.count)
let patterns:[String] = ["(?:~([\(textPattern)]*)~)", "(?:\\*([\(textPattern)]*)\\*)", "(?:<([\(textPattern)]*)>)", "(?:_([\(textPattern)]*)_)"]

for pattern in patterns {
    let regex = try! NSRegularExpression(pattern: pattern)
    regex.enumerateMatches(in: string, range: range, using: { (result, flag, pointer) in 
        if let result = result { 
            for i in 1..<result.numberOfRanges {
                let srange = Range(result.range(at: i))! 
                let start = String.Index(encodedOffset: srange.lowerBound)
                let end = String.Index(encodedOffset: srange.upperBound)
                let substr = String(string[start..<end])
                print("\(result.range(at: i)) => \(substr)")
            }
        }
    })
}

Выход

{1, 8} => Это два
{58, 13} => зачеркнутый
{95, 3} => abc
{16, 9} => полужирный текст
{42, 9} => textcolor
{78, 14} => курсив (слово *)

Обновление: Изменен мой шаблон, чтобы не включать символы формата, ~, * и т. Д., И улучшен вывод в примере, чтобы более четко отображать правильное количество совпадений и совпадения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...