#1381: PhoneNumberUtils.kt
projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt Kotlin-Klasse, projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt 289 Zeilen · 165 Code · 84 Kommentare · 40 Leerzeichen
Zweck: Quelldatei: projectforge/framework/utils/PhoneNumberUtils.kt. PhoneNumberUtils.kt ist Teil der Open-Source-Projektmanagement-Anwendung ProjectForge.
Quellcode (erste 100 Zeilen)
/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2026 Micromata GmbH, Germany (www.micromata.com)
//
// ProjectForge ist dual-lizenziert.
//
// Diese Community-Edition ist freie Software; Sie können es weiterverteilen und/oder
// modifizieren unter den Bedingungen der GNU General Public License, wie veröffentlicht
// von der Free Software Foundation; Version 3 der Lizenz.
//
// Diese Community-Edition wird in der Hoffnung verteilt, dass sie nützlich sein wird,
// aber OHNE JEGLICHE GEWÄHRLEISTUNG; ohne sogar die stillschweigende Garantie der
// MARKTGÄNGIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die GNU General
// Public License für weitere Details.
//
// Sie sollten eine Kopie der GNU General Public License zusammen mit
// diesem Programm erhalten haben; falls nicht, siehe http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.framework.utils
import org.projectforge.framework.configuration.Configuration
import org.projectforge.framework.configuration.ConfigurationParam
/**
* Hilfsfunktionen zur Normalisierung und Formatierung von Telefonnummern.
*
* @author Kai Reinhard (k.reinhard@micromata.de)
*/
object PhoneNumberUtils {
// Häufige Ländervorwahlen (1-3 Ziffern)
private val KNOWN_COUNTRY_CODES = setOf(
"1", // USA, Kanada
"7", // Russland, Kasachstan
"20", "27", // Ägypten, Südafrika
"30", "31", "32", "33", "34", "36", "39", "40", "41", "43", "44", "45", "46", "47", "48", "49", // Europa
"51", "52", "53", "54", "55", "56", "57", "58", // Südamerika
"60", "61", "62", "63", "64", "65", "66", // Asien/Ozeanien
"81", "82", "84", "86", "90", "91", "92", "93", "94", "95", "98", // Asien
"212", "213", "216", "218", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", // Afrika
"230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", // Afrika
"250", "251", "252", "253", "254", "255", "256", "257", "258", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", // Afrika
"290", "291", "297", "298", "299", // Atlantik
"350", "351", "352", "353", "354", "355", "356", "357", "358", "359", // Europa
"370", "371", "372", "373", "374", "375", "376", "377", "378", "380", "381", "382", "383", "385", "386", "387", "389", // Europa
"420", "421", "423", // Europa
"500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", // Amerika
"670", "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", // Pazifik
"850", "852", "853", "855", "856", "880", "886", // Asien
"960", "961", "962", "963", "964", "965", "966", "967", "968", "970", "971", "972", "973", "974", "975", "976", "977", "992", "993", "994", "995", "996", "998" // Asien/Mittlerer Osten
)
/**
* Normalisiert eine Telefonnummer in ein standardisiertes, lesbares Format.
*
* Format: +[Land] [Vorwahl] [Nummer][-Durchwahl]
*
* Beispiele:
* - "0561 316793-0" → "+49 561 316793-0"
* - "+49 (0) 561 / 316793-0" → "+49 561 316793-0"
* - "0170 1234567" → "+49 170 1234567"
* - "+1 415 555-1234" → "+1 415 5551234"
*
* @param phoneNumber Die zu normalisierende Telefonnummer (kann Leerzeichen, Schrägstriche, Klammern usw. enthalten)
* @param defaultCountryPrefix Das zu verwendende Standard-Länderpräfix, falls keines vorhanden ist (Standard: aus Konfiguration oder "+49")
* @return Normalisierte Telefonnummer im Format "+CC AAA NNNNNNN[-EXT]" oder null, wenn die Eingabe null/leer ist
*/
fun normalizePhoneNumber(
phoneNumber: String?,
defaultCountryPrefix: String = getDefaultCountryPrefix()
): String? {
if (phoneNumber.isNullOrBlank()) {
return null
}
var cleaned = phoneNumber.trim()
// Entferne Präfixe wie "Tel:", "Phone:", "Fax:", usw.
cleaned = cleaned.replace(Regex("^(?:Tel\\.?:|Telefon:|Phone:|Mobil:|Mobile:|Fax:)\\s*", RegexOption.IGNORE_CASE), "")
// Entferne UTF-Steuerzeichen
cleaned = cleaned.replace("\\p{C}".toRegex(), "")
// Entferne (0) in +49 (0) 123456789
cleaned = cleaned.replace(Regex("\\(0\\)"), "")
// Entferne Klammern und Schrägstriche frühzeitig für die Erkennung der Ländervorwahl
cleaned = cleaned.replace(Regex("[/()]"), "")
if (cleaned.isEmpty()) {
return null
}
// Gib sehr kurze Nummern (3 Ziffern oder weniger) unverändert zurück - Notrufnummern, Kurzwahlen, usw.
// Beispiele: 0, 00, 110, 112
Git-Verlauf
868d6abb7 2025 -> 2026
2b9888261 Nummernformatierung in Sipgate und vCard-Handhabung umgestaltet.
a2608ee2e PhoneNumberUtils...
c624d79b8 PhoneNumberUtils.formatPhoneNumber und AddressTextParser
868d6abb7
2025 -> 2026868d6abb75cd191a892911ac8e45058932cf9074
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
index 320fb1c99..37ee6ed30 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
@@ -3,7 +3,7 @@
// Project ProjectForge Community Edition
// www.projectforge.org
//
-// Copyright (C) 2001-2025 Micromata GmbH, Germany (www.micromata.com)
+// Copyright (C) 2001-2026 Micromata GmbH, Germany (www.micromata.com)
//
// ProjectForge ist dual-lizenziert.
//
2b9888261
Nummernformatierung in Sipgate und vCard-Handhabung umgestaltet.2b9888261f5880a0d9bda8d7343c4367bd32d7c9
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
index 506ea65ab..320fb1c99 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
@@ -89,21 +89,50 @@ object PhoneNumberUtils {
// Entferne (0) in +49 (0) 123456789
cleaned = cleaned.replace(Regex("\\(0\\)"), "")
+ // Entferne Klammern und Schrägstriche frühzeitig für die Erkennung der Ländervorwahl
+ cleaned = cleaned.replace(Regex("[/()]"), "")
+
if (cleaned.isEmpty()) {
return null
}
+ // Gib sehr kurze Nummern (3 Ziffern oder weniger) unverändert zurück - Notrufnummern, Kurzwahlen, usw.
+ // Beispiele: 0, 00, 110, 112
+ // Aber NICHT, wenn sie mit 00X (internationale Vorwahl) oder +X beginnen
+ val digitCount = cleaned.count { it.isDigit() }
+ if (digitCount in 1..3) {
+ // Erlaube "0", "00", "110", "112" usw. unverändert durchzulaufen
+ // Aber blockiere "001", "0049" usw. (internationales Format) - diese benötigen Verarbeitung
+ if (cleaned == "0" || cleaned == "00" || !cleaned.startsWith("00") && !cleaned.startsWith("+")) {
+ return cleaned
+ }
+ }
+
// Extrahiere Ländervorwahl
- val (countryCode, remainingPart) = extractCountryCode(cleaned, defaultCountryPrefix)
+ val (countryCode, remainingPart, hasPrefix) = extractCountryCode(cleaned, defaultCountryPrefix)
+
+ // Wenn kein Präfix erkannt wurde (kein +, keine 00, keine führende 0), gib die bereinigte Nummer unverändert zurück
+ if (!hasPrefix) {
+ // Bereinige nur Sonderzeichen und normalisiere Leerzeichen
+ val result = cleaned
+ .replace(".", " ")
+ .replace(Regex("\\s+"), " ")
+ .trim()
+ // Aber validiere, dass sie mindestens einige Ziffern enthält
+ if (!result.contains(Regex("\\d"))) {
+ return null
+ }
+ return result
+ }
if (remainingPart.isBlank()) {
- return null
+ // Wenn nur die Ländervorwahl existiert (z.B. "001" -> "+1"), gib nur die Ländervorwahl zurück
+ return countryCode
}
- // Bereinige den verbleibenden Teil: Entferne Punkte, Schrägstriche, Klammern zuerst, dann normalisiere Leerzeichen
+ // Bereinige den verbleibenden Teil: Ersetze Punkte durch Leerzeichen (Trennzeichen), dann normalisiere Leerzeichen
var remaining = remainingPart.trim()
.replace(".", " ") // Punkt ist ein Trennzeichen zwischen Zahlenblöcken
- .replace(Regex("[/()]"), "") // Entferne Schrägstriche, Klammern
.replace(Regex("\\s+"), " ") // Normalisiere mehrere Leerzeichen zu einem Leerzeichen
.trim()
a2608ee2e
PhoneNumberUtils...a2608ee2e9bf20343a26a5543fc0f06176735862
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
index 41a89f714..506ea65ab 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
@@ -100,9 +100,10 @@ object PhoneNumberUtils {
return null
}
- // Bereinige den verbleibenden Teil: Entferne Schrägstriche, Punkte, Klammern zuerst, dann normalisiere Leerzeichen
+ // Bereinige den verbleibenden Teil: Ersetze Punkte durch Leerzeichen (Trennzeichen), entferne Schrägstriche/Klammern, dann normalisiere Leerzeichen
var remaining = remainingPart.trim()
- .replace(Regex("[/().]"), "") // Entferne Schrägstriche, Klammern, Punkte
+ .replace(".", " ") // Punkt ist ein Trennzeichen zwischen Zahlenblöcken
+ .replace(Regex("[/()]"), "") // Entferne Schrägstriche, Klammern
.replace(Regex("\\s+"), " ") // Normalisiere mehrere Leerzeichen zu einem Leerzeichen
.trim()
c624d79b8
PhoneNumberUtils.formatPhoneNumber und AddressTextParserc624d79b8c005f4f746148f647e9eb1dbff3226f
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
new file mode 100644
index 000000000..41a89f714
--- /dev/null
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/utils/PhoneNumberUtils.kt
@@ -0,0 +1,256 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Project ProjectForge Community Edition
+// www.projectforge.org
+//
+// Copyright (C) 2001-2025 Micromata GmbH, Germany (www.micromata.com)
+//
+// ProjectForge ist dual-lizenziert.
+//
+// Diese Community-Edition ist freie Software; Sie können es weiterverteilen und/oder
+// modifizieren unter den Bedingungen der GNU General Public License, wie veröffentlicht
+// von der Free Software Foundation; Version 3 der Lizenz.
+//
+// Diese Community-Edition wird in der Hoffnung verteilt, dass sie nützlich sein wird,
+// aber OHNE JEGLICHE GEWÄHRLEISTUNG; ohne sogar die stillschweigende Garantie der
+// MARKTGÄNGIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die GNU General
+// Public License für weitere Details.
+//
+// Sie sollten eine Kopie der GNU General Public License zusammen mit
+// diesem Programm erhalten haben; falls nicht, siehe http://www.gnu.org/licenses/.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+package org.projectforge.framework.utils
+
+import org.projectforge.framework.configuration.Configuration
+import org.projectforge.framework.configuration.ConfigurationParam
+
+/**
+ * Hilfsfunktionen zur Normalisierung und Formatierung von Telefonnummern.
+ *
+ * @author Kai Reinhard (k.reinhard@micromata.de)
+ */
+object PhoneNumberUtils {
+
+ // Häufige Ländervorwahlen (1-3 Ziffern)
+ private val KNOWN_COUNTRY_CODES = setOf(
+ "1", // USA, Kanada
+ "7", // Russland, Kasachstan
+ "20", "27", // Ägypten, Südafrika
+ "30", "31", "32", "33", "34", "36", "39", "40", "41", "43", "44", "45", "46", "47", "48", "49", // Europa
+ "51", "52", "53", "54", "55", "56", "57", "58", // Südamerika
+ "60", "61", "62", "63", "64", "65", "66", // Asien/Ozeanien
+ "81", "82", "84", "86", "90", "91", "92", "93", "94", "95", "98", // Asien
+ "212", "213", "216", "218", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", // Afrika
+ "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", // Afrika
+ "250", "251", "252", "253", "254", "255", "256", "257", "258", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", // Afrika
+ "290", "291", "297", "298", "299", // Atlantik
+ "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", // Europa
+ "370", "371", "372", "373", "374", "375", "376", "377", "378", "380", "381", "382", "383", "385", "386", "387", "389", // Europa
+ "420", "421", "423", // Europa
+ "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", // Amerika
+ "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", // Pazifik