Roman 2.0.0
dotnet add package Roman --version 2.0.0
NuGet\Install-Package Roman -Version 2.0.0
<PackageReference Include="Roman" Version="2.0.0" />
<PackageVersion Include="Roman" Version="2.0.0" />
<PackageReference Include="Roman" />
paket add Roman --version 2.0.0
#r "nuget: Roman, 2.0.0"
#:package Roman@2.0.0
#addin nuget:?package=Roman&version=2.0.0
#tool nuget:?package=Roman&version=2.0.0
Roman
A small, dependency-free C# library for Roman numerals: conversion to and from Arabic integers, arithmetic, and comparison. Immutable, allocation-light, and fully unit-tested.
π Language: English Β· Π ΡΡΡΠΊΠΈΠΉ
Table of contents
- Features
- Installation
- Quick start
- Usage
- Limitations
- API reference
- Performance
- Testing
- Contributing
- License
Features
- Convert Arabic numbers (1β3999) to Roman and back
- Arithmetic: addition, subtraction, multiplication, division
- Comparison operators:
>,<,>=,<=,==,!= - Implements
IComparable<Roman>andIEquatable<Roman> - Immutable type β every operation returns a new value
- Well-defined
nullsemantics in comparison operators - Case-insensitive parsing with surrounding whitespace trimmed
- Strict (default) and lenient (
RomanStyle.Lenient) parsing modes TryParsefor exception-free parsing- Allocation-light conversion via
stackalloc Span<char> - No external dependencies
Installation
# .NET CLI
dotnet add package Roman
# Package Manager
Install-Package Roman
<PackageReference Include="Roman" Version="1.1.1" />
Quick start
using RomanNumerals;
// From an integer
var a = new Roman(42);
Console.WriteLine(a); // XLII
// From a string
var b = new Roman("XIX");
Console.WriteLine(b.ToInt()); // 19
// Arithmetic
Console.WriteLine(a + b); // LXI (61)
// Comparison
if (a > b)
Console.WriteLine("42 > 19");
// Exception-free parsing
if (Roman.TryParse("MCMXCIV", out var year))
Console.WriteLine(year.ToInt()); // 1994
Note: the type is
Roman, the namespace isRomanNumerals. Addusing RomanNumerals;and usenew Roman(...).
Usage
Creating values
var fromInt = new Roman(1984); // MCMLXXXIV
var fromString = new Roman("MMXXIII"); // 2023
var lower = new Roman(" xlii "); // 42 (trimmed, case-insensitive)
var copy = new Roman(fromInt); // copy constructor
Conversions
// Parse β throws on invalid input
var r1 = Roman.Parse(500);
var r2 = Roman.Parse("D");
// TryParse β never throws
if (Roman.TryParse(42, out var r3)) { /* ... */ }
if (Roman.TryParse("invalid", out var r4)) { /* not reached */ }
// Implicit Roman -> int
int value = new Roman(42); // 42
// Explicit int -> Roman (can throw)
var r5 = (Roman)99; // XCIX
Arithmetic
Operations compute on the underlying integer and re-validate the result against the 1β3999
range, throwing OverflowException when the result overflows (> 3999) or underflows (< 1).
Division is integer division.
new Roman(10) + new Roman(5); // XV (15)
new Roman(50) - new Roman(20); // XXX (30)
new Roman(7) * new Roman(8); // LVI (56)
new Roman(20) / new Roman(4); // V (5)
new Roman(10) / new Roman(3); // III (3, integer division)
new Roman(3999) + new Roman(1); // throws: result > 3999
new Roman(5) - new Roman(5); // throws: result < 1
Comparison
var a = new Roman(50);
var b = new Roman(30);
a > b; // true
a == b; // false
a.CompareTo(b); // > 0
a.Equals(b); // false
null semantics mirror Comparer<T> (null sorts lowest):
Roman x = new Roman(5);
Roman y = null;
x > y; // true (a value is greater than null)
y < x; // true (null is less than any value)
x == y; // false
x != y; // true
Roman p = null, q = null;
p == q; // true
p >= q; // true
Parsing modes (strict / lenient)
By default parsing is strict β it accepts only the canonical form and rejects non-canonical
input such as "IIII". This applies to the constructors, Parse(string) and TryParse(string, β¦):
new Roman("IV"); // OK -> 4
new Roman("IIII"); // FormatException: not canonical
For lenient parsing (accept non-canonical forms), pass RomanStyle.Lenient to the Parse /
TryParse overloads β modeled after int.Parse(string, NumberStyles):
var roman = Roman.Parse("IIII", RomanStyle.Lenient); // parses as 4
Console.WriteLine(roman); // IV (output is always canonical)
if (Roman.TryParse("IIII", RomanStyle.Lenient, out var r))
Console.WriteLine(r); // IV
RomanStyle.Strict (the default) rejects garbage characters (ArgumentException), out-of-range
values (ArgumentOutOfRangeException), and otherwise valid but non-canonical forms
(FormatException).
Limitations
- Range is 1β3999 (
MMMCMXCIX). Values outside this range throwArgumentOutOfRangeException. There is no representation for0or negatives. - Round-trip is value-preserving, not string-preserving.
Roman.Parse("IIII", RomanStyle.Lenient).ToString()returns"IV". Strict parsing (the default) rejects non-canonical input outright. - Arithmetic results must stay within 1β3999, otherwise they throw.
API reference
Constructors
| Constructor | Description |
|---|---|
Roman(int value) |
Creates a value from an integer (1β3999) |
Roman(string roman) |
Creates a value from a string (strict) |
Roman(Roman other) |
Copy constructor |
Static methods
| Method | Description |
|---|---|
Parse(int value) |
Parses an int; throws on error |
Parse(string roman) |
Parses a string (strict); throws on error |
Parse(string roman, RomanStyle style) |
Parses with a mode; Strict throws FormatException on non-canonical input |
TryParse(int value, out Roman? result) |
Exception-free int parsing |
TryParse(string roman, out Roman? result) |
Exception-free string parsing (strict) |
TryParse(string roman, RomanStyle style, out Roman? result) |
Exception-free string parsing with a mode |
Enums
RomanStyle |
Description |
|---|---|
Strict |
Strict parsing (default): canonical form only |
Lenient |
Lenient parsing: accepts non-canonical forms |
Instance methods
| Method | Description |
|---|---|
ToInt() |
Returns the Arabic value |
ToString() |
Returns the canonical Roman string |
CompareTo(Roman? other) |
Compares with another value |
Equals(Roman? other) |
Value equality |
GetHashCode() |
Hash code |
Operators
| Operator | Description |
|---|---|
+ - * / |
Arithmetic (integer division) |
> < >= <= |
Comparison (null sorts lowest) |
== != |
Equality |
(int)roman |
Implicit conversion Roman -> int |
(Roman)value |
Explicit conversion int -> Roman |
Performance
The conversion path is allocation-light:
- The
int -> Romanconversion writes into astackalloc Span<char>buffer β no heap allocation beyond the resulting string. - The type is immutable and wraps a single
int, so instances are cheap to copy and compare.
Testing
The library ships with a comprehensive MSTest suite covering constructors, arithmetic, comparison, parsing (both modes), conversions, and int β Roman β string round-trips.
dotnet test # run all tests
dotnet test --collect:"XPlat Code Coverage" # with coverage
Contributing
Issues and pull requests are welcome. When filing a bug, please include the library version, the .NET version, a minimal reproduction, and the expected vs. actual behavior.
License
Licensed under the MIT License.
Author
deliciousNesquik β @deliciousNesquik
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.