[DeckList] Refactor load from plaintext to take normalizer as param (#6664)

* [DeckList] Refactor load from plaintext to take normalizer as param

* update usages

* weaken unit test

* weaken unit test more

* revert unit test

* move CardNameNormalizer to libcockatrice_card

* update unit test

* formatting
This commit is contained in:
RickyRister 2026-03-06 10:39:04 -08:00 committed by GitHub
parent bd5cbb89d4
commit dead993639
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 94 additions and 52 deletions

View file

@ -199,9 +199,12 @@ bool DeckList::saveToFile_Native(QIODevice *device) const
*
* @param in The text to load
* @param preserveMetadata If true, don't clear the existing metadata
* @param cardNameNormalizer Function that takes the parsed card name string in the text and
* @return False if the input was empty, true otherwise.
*/
bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata)
bool DeckList::loadFromStream_Plain(QTextStream &in,
bool preserveMetadata,
const std::function<QString(const QString &)> &cardNameNormalizer)
{
const QRegularExpression reCardLine(R"(^\s*[\w\[\(\{].*$)", QRegularExpression::UseUnicodePropertiesOption);
const QRegularExpression reEmpty("^\\s*$");
@ -213,23 +216,11 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata)
// Regex for advanced card parsing
const QRegularExpression reMultiplier(R"(^[xX\(\[]*(\d+)[xX\*\)\]]* ?(.+))");
const QRegularExpression reSplitCard(R"( ?\/\/ ?)");
const QRegularExpression reBrace(R"( ?[\[\{][^\]\}]*[\]\}] ?)"); // not nested
const QRegularExpression reRoundBrace(R"(^\([^\)]*\) ?)"); // () are only matched at start of string
const QRegularExpression reDigitBrace(R"( ?\(\d*\) ?)"); // () are matched if containing digits
const QRegularExpression reBraceDigit(
R"( ?\([\dA-Z]+\) *\d+$)"); // () are matched if containing setcode then a number
const QRegularExpression reDoubleFacedMarker(R"( ?\(Transform\) ?)");
// Regex for extracting set code and collector number with attached symbols
const QRegularExpression reHyphenFormat(R"(\((\w{3,})\)\s+(\w{3,})-(\d+[^\w\s]*))");
const QRegularExpression reRegularFormat(R"(\((\w{3,})\)\s+(\d+[^\w\s]*))");
const QHash<QRegularExpression, QString> differences{{QRegularExpression(""), QString("'")},
{QRegularExpression("Æ"), QString("Ae")},
{QRegularExpression("æ"), QString("ae")},
{QRegularExpression(" ?[|/]+ ?"), QString(" // ")}};
cleanList(preserveMetadata);
auto inputs = in.readAll().trimmed().split('\n');
@ -355,26 +346,8 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata)
cardName = match.captured(2);
}
// Handle advanced card types
if (cardName.contains(reSplitCard)) {
cardName = cardName.split(reSplitCard).join(" // ");
}
if (cardName.contains(reDoubleFacedMarker)) {
QStringList faces = cardName.split(reDoubleFacedMarker);
cardName = faces.first().trimmed();
}
// Remove unnecessary characters
cardName.remove(reBrace);
cardName.remove(reRoundBrace); // I'll be entirely honest here, these are split to accommodate just three cards
cardName.remove(reDigitBrace); // from un-sets that have a word in between round braces at the end
cardName.remove(reBraceDigit); // very specific format with the set code in () and collectors number after
// Normalize names
for (auto diff = differences.constBegin(); diff != differences.constEnd(); ++diff) {
cardName.replace(diff.key(), diff.value());
}
// Normalize the card name
cardName = cardNameNormalizer(cardName);
// Determine the zone (mainboard/sideboard)
QString zoneName = sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
@ -387,10 +360,10 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata)
return true;
}
bool DeckList::loadFromFile_Plain(QIODevice *device)
bool DeckList::loadFromFile_Plain(QIODevice *device, const std::function<QString(const QString &)> &cardNameNormalizer)
{
QTextStream in(device);
return loadFromStream_Plain(in, false);
return loadFromStream_Plain(in, false, cardNameNormalizer);
}
bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const

View file

@ -206,8 +206,10 @@ public:
/// @name Serialization (Plain text)
///@{
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
bool loadFromFile_Plain(QIODevice *device);
bool loadFromStream_Plain(QTextStream &stream,
bool preserveMetadata,
const std::function<QString(const QString &)> &cardNameNormalizer);
bool loadFromFile_Plain(QIODevice *device, const std::function<QString(const QString &)> &cardNameNormalizer);
bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const;
bool
saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false) const;