Skip to content

Commit

Permalink
fix #269467: added stringutils class to support searching without acc…
Browse files Browse the repository at this point in the history
…ents, added tests in mtest
  • Loading branch information
finleylau committed Feb 27, 2018
1 parent 84b414a commit 5dd85bd
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 1 deletion.
1 change: 1 addition & 0 deletions mscore/CMakeLists.txt
Expand Up @@ -238,6 +238,7 @@ add_executable ( ${ExecutableName}
${INCS}

recordbutton.h greendotbutton prefsdialog.h prefsdialog.cpp
stringutils.h stringutils.cpp
scoreview.cpp editharmony.cpp editfiguredbass.cpp events.cpp
editinstrument.cpp editstyle.cpp
icons.cpp importbww.cpp
Expand Down
8 changes: 7 additions & 1 deletion mscore/instrwidget.cpp
Expand Up @@ -21,6 +21,7 @@
#include "config.h"
#include "icons.h"
#include "instrwidget.h"
#include "stringutils.h"

#include "libmscore/clef.h"
#include "libmscore/instrtemplate.h"
Expand Down Expand Up @@ -56,7 +57,12 @@ void filterInstruments(QTreeWidget* instrumentList, const QString &searchPhrase)
for (int cidx = 0; (ci = item->child(cidx)); ++cidx) {
// replace the unicode b (accidental) so a search phrase of "bb" would give Bb Trumpet...
QString text = ci->text(0).replace(QChar(0x266d), QChar('b'));
bool isMatch = text.contains(searchPhrase, Qt::CaseInsensitive);

// remove ligatures and diacritics
QString removedSpecialChar = stringutils::removeLigatures(text);
removedSpecialChar = stringutils::removeDiacritics(removedSpecialChar);

bool isMatch = text.contains(searchPhrase, Qt::CaseInsensitive) || removedSpecialChar.contains(searchPhrase, Qt::CaseInsensitive);
ci->setHidden(!isMatch);

if (isMatch)
Expand Down
98 changes: 98 additions & 0 deletions mscore/stringutils.cpp
@@ -0,0 +1,98 @@
//=============================================================================
// MuseScore
// Linux Music Score Editor
// Copyright (C) 2002-2018 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================

#include "stringutils.h"

namespace Ms {

//---------------------------------------------------------
// removeLigatures
//---------------------------------------------------------

QString stringutils::removeLigatures(const QString& pre)
{
QString result = pre;

// Characters with above dots (Ae, ae, Oe, oe, Ue, ue
result = result.replace(QRegularExpression("[\\x{00C4}]"), QString("Ae"));
result = result.replace(QRegularExpression("[\\x{00E4}]"), QString("ae"));
result = result.replace(QRegularExpression("[\\x{00D6}]"), QString("Oe"));
result = result.replace(QRegularExpression("[\\x{00F6}]"), QString("oe"));
result = result.replace(QRegularExpression("[\\x{00DC}]"), QString("Ue"));
result = result.replace(QRegularExpression("[\\x{00FC}]"), QString("ue"));

// Latin Big Letter AA (&#42802) and Latin Small Letter aa (&#42803)
result = result.replace(QRegularExpression("[\\x{A732}]"), QString("Aa"));
result = result.replace(QRegularExpression("[\\x{A733}]"), QString("aa"));

// Latin Big Letter AE (&#198) and Latin Small Letter ae (&#230)
result = result.replace(QRegularExpression("[\\x{00C6}]"), QString("Ae"));
result = result.replace(QRegularExpression("[\\x{00E6}]"), QString("ae"));

// Latin Big Letter AO (&#42804) and Latin Small Letter ao (&#42805)
result = result.replace(QRegularExpression("[\\x{A734}]"), QString("Ao"));
result = result.replace(QRegularExpression("[\\x{A735}]"), QString("ao"));

// Latin Big Letter AU (&#42806) and Latin Small Letter au (&#42807)
result = result.replace(QRegularExpression("[\\x{A736}]"), QString("Au"));
result = result.replace(QRegularExpression("[\\x{A737}]"), QString("au"));

// IJ (&#306) and ij (&#307)
result = result.replace(QRegularExpression("[\\x{0132}]"), QString("IJ"));
result = result.replace(QRegularExpression("[\\x{0133}]"), QString("ij"));

// Eszett SS (&#7838) and ss (&#223)
result = result.replace(QRegularExpression("[\\x{1E9E}]"), QString("SS"));
result = result.replace(QRegularExpression("[\\x{00DF}]"), QString("ss"));

// O with stroke (&#216) and o with stroke (&#248)
result = result.replace(QRegularExpression("[\\x{00D8}]"), QChar('O'));
result = result.replace(QRegularExpression("[\\x{00F8}]"), QChar('o'));

// Big Letter OE (&#338) and small letter oe (&#339)
result = result.replace(QRegularExpression("[\\x{0152}]"), QString("Oe"));
result = result.replace(QRegularExpression("[\\x{0153}]"), QString("oe"));

// Big Letter OO (&#42830) and small letter oo (&#42831)
result = result.replace(QRegularExpression("[\\x{A74E}]"), QString("Oo"));
result = result.replace(QRegularExpression("[\\x{A74F}]"), QString("oo"));

// ue (&#7531)
result = result.replace(QRegularExpression("[\\x{1D6B}]"), QString("ue"));

return result;
}

//---------------------------------------------------------
// removeDiacritics
//---------------------------------------------------------

QString stringutils::removeDiacritics(const QString& pre)
{
QString text = pre.normalized(QString::NormalizationForm_KD);
QString result;
for (int i = 0; i < text.length(); ++i) {
if (text.at(i).category() != QChar::Mark_NonSpacing) {
result.append(text.at(i));
}
}
result = result.normalized(QString::NormalizationForm_C);
return result;
}

} // namespace Ms
37 changes: 37 additions & 0 deletions mscore/stringutils.h
@@ -0,0 +1,37 @@
//=============================================================================
// MuseScore
// Linux Music Score Editor
// Copyright (C) 2002-2018 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================

#ifndef STRINGUTILS_H
#define STRINGUTILS_H

#include <QObject>

namespace Ms {

class stringutils : public QObject
{
Q_OBJECT

public:
static QString removeLigatures(const QString& pre);
static QString removeDiacritics(const QString& pre);
};

} // namespace Ms

#endif // STRINGUTILS_H
2 changes: 2 additions & 0 deletions mtest/CMakeLists.txt
Expand Up @@ -92,6 +92,7 @@ add_library(
${PROJECT_SOURCE_DIR}/mscore/qmlplugin.cpp
${PROJECT_SOURCE_DIR}/mscore/preferences.cpp
${PROJECT_SOURCE_DIR}/mscore/shortcut.cpp
${PROJECT_SOURCE_DIR}/mscore/stringutils.cpp
${PROJECT_SOURCE_DIR}/thirdparty/rtf2html/fmt_opts.cpp # Required by capella.cpp and capxml.cpp
${PROJECT_SOURCE_DIR}/thirdparty/rtf2html/rtf2html.cpp # Required by capella.cpp and capxml.cpp
${PROJECT_SOURCE_DIR}/thirdparty/rtf2html/rtf_keyword.cpp # Required by capella.cpp and capxml.cpp
Expand Down Expand Up @@ -208,6 +209,7 @@ subdirs (
musicxml
guitarpro
scripting
stringutils
# testoves
zerberus/comments
zerberus/envelopes
Expand Down
16 changes: 16 additions & 0 deletions mtest/stringutils/CMakeLists.txt
@@ -0,0 +1,16 @@
#=============================================================================
# MuseScore
# Music Composition & Notation
# $Id:$
#
# Copyright (C) 2018 Werner Schweer
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation and appearing in
# the file LICENSE.GPL
#=============================================================================

set(TARGET tst_stringutils)

include(${PROJECT_SOURCE_DIR}/mtest/cmake.inc)
126 changes: 126 additions & 0 deletions mtest/stringutils/tst_stringutils.cpp
@@ -0,0 +1,126 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
// $Id:$
//
// Copyright (C) 2018 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================

#include <QtTest/QtTest>
#include <QVector>
#include "mtest/testutils.h"
#include "mscore/stringutils.h"

#define DIR QString("stringutils/")

using namespace Ms;

//---------------------------------------------------------
// TestStringUtils
//---------------------------------------------------------

class TestStringUtils : public QObject, public MTest
{
Q_OBJECT

private slots:
void initTestCase();
void tst_stringutils();
};

//---------------------------------------------------------
// initTestCase
//---------------------------------------------------------

void TestStringUtils::initTestCase()
{
initMTest();
}

//---------------------------------------------------------
// stringutils
//---------------------------------------------------------

void TestStringUtils::tst_stringutils()
{
QString testEnglish("Test test");
QVERIFY(stringutils::removeDiacritics(testEnglish) == testEnglish);
QVERIFY(stringutils::removeLigatures(testEnglish) == testEnglish);

QString testNonLatin1("Πκολο");
QVERIFY(stringutils::removeDiacritics(testNonLatin1) == testNonLatin1);
QVERIFY(stringutils::removeLigatures(testNonLatin1) == testNonLatin1);

QString testNonLatin2("超倍低音长笛");
QVERIFY(stringutils::removeDiacritics(testNonLatin2) == testNonLatin2);
QVERIFY(stringutils::removeLigatures(testNonLatin2) == testNonLatin2);

QString testNonLatin3("פיקולו");
QVERIFY(stringutils::removeDiacritics(testNonLatin3) == testNonLatin3);
QVERIFY(stringutils::removeLigatures(testNonLatin3) == testNonLatin3);

QString testNonLatin4("پیکولو");
QVERIFY(stringutils::removeDiacritics(testNonLatin4) == testNonLatin4);
QVERIFY(stringutils::removeLigatures(testNonLatin4) == testNonLatin4);

const QVector<QChar> ligatureVector({
QChar(0xA732),
QChar(0xA733),
QChar(0x00C6),
QChar(0x00C4),
QChar(0x00E6),
QChar(0x00E4),
QChar(0xA734),
QChar(0xA735),
QChar(0xA736),
QChar(0xA737),
QChar(0x0132),
QChar(0x0133),
QChar(0x1E9E),
QChar(0x00DF),
QChar(0x00D8),
QChar(0x00F8),
QChar(0x0152),
QChar(0x00D6),
QChar(0x0153),
QChar(0x00F6),
QChar(0xA74E),
QChar(0xA74F),
QChar(0x00DC),
QChar(0x00FC),
QChar(0x1D6B)});
QString testLigatures;
for (int i = 0; i < ligatureVector.size(); i++) {
testLigatures.append(ligatureVector.at(i));
}
QVERIFY(stringutils::removeLigatures(testLigatures) == QString("AaaaAeAeaeaeAoaoAuauIJijSSssOoOeOeoeoeOoooUeueue"));

const QVector<QChar> diacriticVector({
QChar(0x00E9), // acute e
QChar(0x00C9), // acute E
QChar(0x00E8), // grave e
QChar(0x00C8), // grave E
QChar(0x00EA), // circumflex e
QChar(0x00CA), // circumflex E
QChar(0x00E7), // cedilla c
QChar(0x00C7), // cedilla C
QChar(0x00F1), // tilde n
QChar(0x00D1), // tilde N
QChar(0x00E5), // ring a
QChar(0x00C5), // ring A
QChar(0x010D), // caron c
QChar(0x010C)}); // caron C
QString testDiacritics;
for (int i = 0; i < diacriticVector.size(); i++) {
testDiacritics.append(diacriticVector.at(i));
}
QVERIFY(stringutils::removeDiacritics(testDiacritics) == QString("eEeEeEcCnNaAcC"));
}

QTEST_MAIN(TestStringUtils)
#include "tst_stringutils.moc"

0 comments on commit 5dd85bd

Please sign in to comment.