/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights resvered.
*/
package commonmark4cj.commonmark
/**
* Functions for finding characters in strings or checking characters.
*/
public class Characters {
public static func find(c: Byte, s: String, startIndex: Int): Int {
let length = s.size
for (i in startIndex..length) {
if (s[i] == c) {
return i
}
}
return -1
}
public static func findLineBreak(s: String, startIndex: Int): Int {
let length = s.size
for (i in startIndex..length) {
match (s[i]) {
case b'\n' | b'\r' => return i
case _ => ()
}
}
return -1
}
/**
* @see <a href="spec/commonmark/org/0.31.2/#blank-line">blank line</a>
*/
public static func isBlank(s: String): Bool {
return skipSpaceTab(s, 0, s.size) == s.size
}
public static func hasNonSpace(s: String): Bool {
let length = s.size
let skipped = skip(b' ', s, 0, length)
return skipped != length
}
public static func isLetter(s: String, index: Int): Bool {
let codePoint = Rune.fromUtf8(unsafe { s.rawData() }, index)
return codePoint[0].isLetter()
}
public static func isSpaceOrTab(s: String, index: Int): Bool {
if (index < s.size) {
match (s[index]) {
case b' ' | b'\t' => return true
case _ => ()
}
}
return false
}
/**
* @see <a href="spec/commonmark/org/0.31.2/#unicode-punctuation-character">Unicode punctuation character</a>
*/
public static var isPunctuationCodePoint: (Rune) -> Bool = {
codePoint: Rune =>
/*
* An ASCII punctuation character is
* !, ", #, $, %, &, ', (, ), *, +, ,, -, ., / (U+0021–2F)
* :, ;, <, =, >, ?, @ (U+003A–0040)
* [, \, ], ^, _, ` (U+005B–0060)
* {, |, }, or ~ (U+007B–007E)
*/
match {
case r'!' <= codePoint && codePoint <= r'.' => return true
case r':' <= codePoint && codePoint <= r'@' => return true
case r'[' <= codePoint && codePoint <= r'`' => return true
case r'{' <= codePoint && codePoint <= r'~' => return true
case _ => ()
}
let code = UInt32(codePoint)
// 补充一些常用中文标点
if (0x3000 <= code && code <= 0x303F) {
return true
}
// 补充一些全角标点
if (0xFF00 <= code && code <= 0xFFEF) {
if (0xFF01 <= code && code <= 0xFF0F) {
return true
}
if (0xFF1A <= code && code <= 0xFF20) {
return true
}
if (0xFF3B <= code && code <= 0xFF40) {
return true
}
if (0xFF5B <= code && code <= 0xFF64) {
return true
}
if (0xFFE0 <= code && code <= 0xFFEE) {
return true
}
}
return false
}
/**
* Check whether the provided code point is a Unicode whitespace character as defined in the spec.
*
* @see <a href="spec/commonmark/org/0.31.2/#unicode-whitespace-character">Unicode whitespace character</a>
*/
public static func isWhitespaceCodePoint(codePoint: Rune): Bool {
match (codePoint) {
case ' ' | '\t' | '\n' | '\f' | '\r' => return true
case _ => return codePoint.isWhiteSpace()
}
}
public static func skip(skip: Byte, s: String, startIndex: Int, endIndex: Int): Int {
for (i in startIndex..endIndex) {
if (s[i] != skip) {
return i
}
}
return endIndex
}
public static func skipBackwards(skip: Byte, s: String, startIndex: Int, lastIndex: Int): Int {
for (i in startIndex..=lastIndex : -1) {
if (s[i] != skip) {
return i
}
}
return lastIndex - 1
}
public static func skipSpaceTab(s: String, startIndex: Int, endIndex: Int): Int {
for (i in startIndex..endIndex) {
match (s[i]) {
case b' ' | b'\t' => ()
case _ => return i
}
}
return endIndex
}
public static func skipSpaceTabBackwards(s: String, startIndex: Int, lastIndex: Int): Int {
for (i in startIndex..=lastIndex : -1) {
match (s[i]) {
case b' ' | b'\t' => ()
case _ => return i
}
}
return lastIndex - 1
}
}