Add Iroha-style numbering (+ bugfix) (#555)
This commit is contained in:
parent
0f8219b392
commit
5cb226026e
@ -36,8 +36,9 @@ use crate::text::Case;
|
||||
pub fn numbering(
|
||||
/// Defines how the numbering works.
|
||||
///
|
||||
/// **Counting symbols** are `1`, `a`, `A`, `i`, `I` and `*`. They are
|
||||
/// replaced by the number in the sequence, in the given case.
|
||||
/// **Counting symbols** are `1`, `a`, `A`, `i`, `I`, `い`, `イ`,
|
||||
/// `א`, and `*`. They are replaced by the number in the sequence,
|
||||
/// in the given case.
|
||||
///
|
||||
/// The `*` character means that symbols should be used to count, in the
|
||||
/// order of `*`, `†`, `‡`, `§`, `¶`, and `‖`. If there are more than six
|
||||
@ -129,8 +130,8 @@ cast_to_value! {
|
||||
|
||||
/// How to turn a number into text.
|
||||
///
|
||||
/// A pattern consists of a prefix, followed by one of `1`, `a`, `A`, `i`, `I`
|
||||
/// or `*`, and then a suffix.
|
||||
/// A pattern consists of a prefix, followed by one of `1`, `a`, `A`, `i`,
|
||||
/// `I`, `い`, `イ`, `א`, or `*`, and then a suffix.
|
||||
///
|
||||
/// Examples of valid patterns:
|
||||
/// - `1)`
|
||||
@ -256,6 +257,8 @@ enum NumberingKind {
|
||||
Roman,
|
||||
Symbol,
|
||||
Hebrew,
|
||||
HiraganaIroha,
|
||||
KatakanaIroha,
|
||||
}
|
||||
|
||||
impl NumberingKind {
|
||||
@ -267,6 +270,8 @@ impl NumberingKind {
|
||||
'i' => NumberingKind::Roman,
|
||||
'*' => NumberingKind::Symbol,
|
||||
'א' => NumberingKind::Hebrew,
|
||||
'い' => NumberingKind::HiraganaIroha,
|
||||
'イ' => NumberingKind::KatakanaIroha,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@ -279,6 +284,8 @@ impl NumberingKind {
|
||||
Self::Roman => 'i',
|
||||
Self::Symbol => '*',
|
||||
Self::Hebrew => 'א',
|
||||
Self::HiraganaIroha => 'い',
|
||||
Self::KatakanaIroha => 'イ',
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,29 +295,37 @@ impl NumberingKind {
|
||||
Self::Arabic => {
|
||||
eco_format!("{n}")
|
||||
}
|
||||
Self::Letter => {
|
||||
if n == 0 {
|
||||
return '-'.into();
|
||||
}
|
||||
|
||||
n -= 1;
|
||||
|
||||
let mut letters = vec![];
|
||||
loop {
|
||||
let c = b'a' + (n % 26) as u8;
|
||||
letters.push(match case {
|
||||
Case::Lower => c,
|
||||
Case::Upper => c.to_ascii_uppercase(),
|
||||
});
|
||||
n /= 26;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
letters.reverse();
|
||||
String::from_utf8(letters).unwrap().into()
|
||||
}
|
||||
Self::Letter => zeroless::<26>(
|
||||
|x| match case {
|
||||
Case::Lower => char::from(b'a' + x as u8),
|
||||
Case::Upper => char::from(b'A' + x as u8),
|
||||
},
|
||||
n,
|
||||
),
|
||||
Self::HiraganaIroha => zeroless::<47>(
|
||||
|x| {
|
||||
[
|
||||
'い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る',
|
||||
'を', 'わ', 'か', 'よ', 'た', 'れ', 'そ', 'つ', 'ね', 'な', 'ら',
|
||||
'む', 'う', 'ゐ', 'の', 'お', 'く', 'や', 'ま', 'け', 'ふ', 'こ',
|
||||
'え', 'て', 'あ', 'さ', 'き', 'ゆ', 'め', 'み', 'し', 'ゑ', 'ひ',
|
||||
'も', 'せ', 'す',
|
||||
][x]
|
||||
},
|
||||
n,
|
||||
),
|
||||
Self::KatakanaIroha => zeroless::<47>(
|
||||
|x| {
|
||||
[
|
||||
'イ', 'ロ', 'ハ', 'ニ', 'ホ', 'ヘ', 'ト', 'チ', 'リ', 'ヌ', 'ル',
|
||||
'ヲ', 'ワ', 'カ', 'ヨ', 'タ', 'レ', 'ソ', 'ツ', 'ネ', 'ナ', 'ラ',
|
||||
'ム', 'ウ', 'ヰ', 'ノ', 'オ', 'ク', 'ヤ', 'マ', 'ケ', 'フ', 'コ',
|
||||
'エ', 'テ', 'ア', 'サ', 'キ', 'ユ', 'メ', 'ミ', 'シ', 'ヱ', 'ヒ',
|
||||
'モ', 'セ', 'ス',
|
||||
][x]
|
||||
},
|
||||
n,
|
||||
),
|
||||
Self::Roman => {
|
||||
if n == 0 {
|
||||
return 'N'.into();
|
||||
@ -420,3 +435,43 @@ impl NumberingKind {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stringify a number using a base-N counting system with no zero digit.
|
||||
///
|
||||
/// This is best explained by example. Suppose our digits are 'A', 'B', and 'C'.
|
||||
/// we would get the following:
|
||||
///
|
||||
/// ```text
|
||||
/// 1 => "A"
|
||||
/// 2 => "B"
|
||||
/// 3 => "C"
|
||||
/// 4 => "AA"
|
||||
/// 5 => "AB"
|
||||
/// 6 => "AC"
|
||||
/// 7 => "BA"
|
||||
/// 8 => "BB"
|
||||
/// 9 => "BC"
|
||||
/// 10 => "CA"
|
||||
/// 11 => "CB"
|
||||
/// 12 => "CC"
|
||||
/// 13 => "AAA"
|
||||
/// etc.
|
||||
/// ```
|
||||
///
|
||||
/// You might be familiar with this scheme from the way spreadsheet software
|
||||
/// tends to label its columns.
|
||||
fn zeroless<const N_DIGITS: usize>(
|
||||
mk_digit: impl Fn(usize) -> char,
|
||||
mut n: usize,
|
||||
) -> EcoString {
|
||||
if n == 0 {
|
||||
return '-'.into();
|
||||
}
|
||||
let mut cs = vec![];
|
||||
while n > 0 {
|
||||
n -= 1;
|
||||
cs.push(mk_digit(n % N_DIGITS));
|
||||
n /= N_DIGITS;
|
||||
}
|
||||
cs.into_iter().rev().collect()
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 29 KiB |
@ -9,6 +9,25 @@
|
||||
parbreak()
|
||||
}
|
||||
|
||||
---
|
||||
#for i in range(0, 4) {
|
||||
numbering("A", i)
|
||||
[ for #i]
|
||||
linebreak()
|
||||
}
|
||||
#par[...]
|
||||
#for i in range(26, 30) {
|
||||
numbering("A", i)
|
||||
[ for #i]
|
||||
linebreak()
|
||||
}
|
||||
#par[...]
|
||||
#for i in range(702, 706) {
|
||||
numbering("A", i)
|
||||
[ for #i]
|
||||
linebreak()
|
||||
}
|
||||
|
||||
---
|
||||
// Error: 17-19 number must be at least zero
|
||||
#numbering("1", -1)
|
||||
@ -21,3 +40,26 @@
|
||||
[ עבור #i]
|
||||
parbreak()
|
||||
}
|
||||
|
||||
---
|
||||
#for i in range(0, 4) {
|
||||
numbering("イ", i)
|
||||
[ (or ]
|
||||
numbering("い", i)
|
||||
[) for #i]
|
||||
linebreak()
|
||||
}
|
||||
#par[...]
|
||||
#for i in range(47, 51) {
|
||||
numbering("イ", i)
|
||||
[ (or ]
|
||||
numbering("い", i)
|
||||
[) for #i]
|
||||
linebreak()
|
||||
}
|
||||
#par[...]
|
||||
#for i in range(2256, 2260) {
|
||||
numbering("イ", i)
|
||||
[ for #i]
|
||||
linebreak()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user