- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我需要经常调用这个函数。基本上,它将所有带重音的字符替换为其无重音的等效字符,将空格更改为“_”,转换为小写,并去除其余的外来代码,因此可以安全地用作文件名/url 路径/等。问题是,如您所见,从性能的角度来看,它看起来很糟糕。谁能想到更清洁、更快的替代方案?
public static String makeValidPathName(String rawString) {
if (rawString==null) return null;
rawString = rawString.replaceAll("[ÁÀÂÄáàäaàáâãäå]","a");
rawString = rawString.replaceAll("æ","ae");
rawString = rawString.replaceAll("çÇ","c");
rawString = rawString.replaceAll("[ÈÉÊËèéêë]","e");
rawString = rawString.replaceAll("[ìíîïÍÌÎÏ]","i");
rawString = rawString.replaceAll("ñÑ","n");
rawString = rawString.replaceAll("[ÓÓÖÔòóôõö]","o");
rawString = rawString.replaceAll("œ","oe");
rawString = rawString.replaceAll("[ÙÚÛÜùúûü]", "u");
rawString = rawString.replaceAll("[ýÿ]","y");
rawString= rawString.replaceAll("[^a-z A-Z 0-9 \\_ \\+]","");
rawString = rawString.replaceAll(" ","_");
return rawString.toLowerCase();
}
--- 编辑
好的,伙计们......我对所有 4 种情况都进行了性能测试:
然后...获胜者是...TADAAA .....
D/REPLACEMENT_TEST(18563): *** Running Tests (1000 iterations)
D/REPLACEMENT_TEST(18563): Original REGEX : 13533 ms
D/REPLACEMENT_TEST(18563): Compiled REGEX : 12563 ms
D/REPLACEMENT_TEST(18563): Character LUT : 1840 ms
D/REPLACEMENT_TEST(18563): Java NORMALIZER : 2416 ms
测试是在 Samsung Galaxy Tab v1 10.1 中完成的。
请在附件中找到测试用例的源代码。
public class Misc {
/* Test 2 (@WCChargin's Regex compilation) initialization */
static Map<Pattern, String> patterns = new HashMap<Pattern, String>();
static {
patterns.put(Pattern.compile("[ÁÀÂÄáàäaàáâãäå]") ,"a");
patterns.put(Pattern.compile("æ"),"ae");
patterns.put(Pattern.compile("çÇ"),"c");
patterns.put(Pattern.compile("[ÈÉÊËèéêë]"),"e");
patterns.put(Pattern.compile("[ìíîïÍÌÎÏ]"),"i");
patterns.put(Pattern.compile("ñÑ"),"n");
patterns.put(Pattern.compile("[ÓÓÖÔòóôõö]"),"o");
patterns.put(Pattern.compile("œ"),"oe");
patterns.put(Pattern.compile("[ÙÚÛÜùúûü]"), "u");
patterns.put(Pattern.compile("[ýÿ]"),"y");
patterns.put(Pattern.compile("[^a-z A-Z 0-9 \\_ \\+]"),"");
patterns.put(Pattern.compile(" "),"_");
}
/* Test 3 (@devconsole's Lookup table) initialization */
static SparseArray<String> homeBrewPatterns=new SparseArray<String>();
/** helper function to fill the map where many different chars map to the same replacement */
static void fillMap(String chars, String replacement) { for (int i=0,len=chars.length(); i<len; i++) homeBrewPatterns.put(chars.charAt(i), replacement); }
static {
// fill the sparsearray map with all possible substitutions: Any char code gets its equivalent, ie, ä->a. a->a. A->a
// this also does the toLowerCase automatically. If a char is not in the list, it is forbidden and we skip it.
fillMap("ÁÀÂÄáàäaàáâãäå","a");
fillMap("æ","ae");
fillMap("çÇ","c");
fillMap("ÈÉÊËèéêë","e");
fillMap("ìíîïÍÌÎÏ","i");
fillMap("ñÑ","n");
fillMap("ÓÓÖÔòóôõö","o");
fillMap("œ","oe");
fillMap("ÙÚÛÜùúûü","u");
fillMap("ýÿ","y");
fillMap(" ","_");
for (char c='a'; c<='z'; c++) fillMap(""+c,""+c); // fill standard ASCII lowercase -> same letter
for (char c='A'; c<='Z'; c++) fillMap(""+c,(""+c).toLowerCase()); // fill standard ASCII uppercase -> uppercase
for (char c='0'; c<='9'; c++) fillMap(""+c,""+c); // fill numbers
}
/** FUNCTION TO TEST #1: Original function, no pattern compilation */
public static String makeValidPathName(String rawString) {
if (rawString==null) return null;
rawString = rawString.replaceAll("[ÁÀÂÄáàäaàáâãäå]","a");
rawString = rawString.replaceAll("æ","ae");
rawString = rawString.replaceAll("çÇ","c");
rawString = rawString.replaceAll("[ÈÉÊËèéêë]","e");
rawString = rawString.replaceAll("[ìíîïÍÌÎÏ]","i");
rawString = rawString.replaceAll("ñÑ","n");
rawString = rawString.replaceAll("[ÓÓÖÔòóôõö]","o");
rawString = rawString.replaceAll("œ","oe");
rawString = rawString.replaceAll("[ÙÚÛÜùúûü]", "u");
rawString = rawString.replaceAll("[ýÿ]","y");
rawString = rawString.replaceAll("[^a-z A-Z 0-9 \\_ \\+]","");
rawString = rawString.replaceAll(" ","_");
return rawString.toLowerCase();
}
/** FUNCTION TO TEST #2: @WCChargin's suggestion: Compile patterns then iterate a map */
public static String makeValidPathName_compiled(String rawString) {
for (Map.Entry<Pattern, String> e : patterns.entrySet()) {
rawString=e.getKey().matcher(rawString).replaceAll(e.getValue());
}
return rawString.toLowerCase();
}
/** FUNCTION TO TEST #3: @devconsole's suggestion: Create a LUT with all equivalences then append to a stringbuilder */
public static String makeValidPathName_lut(String rawString) {
StringBuilder purified=new StringBuilder(rawString.length()); // to avoid resizing
String aux; // to avoid creating objects inside the for
for (int i=0, len=rawString.length(); i<len; i++) {
aux=homeBrewPatterns.get(rawString.charAt(i));
if (aux!=null) purified.append(aux);
}
return purified.toString();
}
/** FUNCTION TO TEST #4: @Erik Pragt's suggestion on the use of a Normalizer */
public static String makeValidPathName_normalizer(String rawString) {
return rawString == null ? null
: Normalizer.normalize(rawString, Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
}
/** Test Runner as a Runnable, just do a Handler.post() to run it */
public static Runnable msStringReplacementTest=new Runnable() {
public void run() {
String XTAG="REPLACEMENT_TEST";
Log.d(XTAG, "*** Running Tests");
int ITERATIONS=1000;
String[] holder=new String[4];
/* http://www.adhesiontext.com/ to generate dummy long text ... its late n im tired :) */
String tester="e arte nací valse ojales i demediada cesé entrañan domó reo ere fiaréis cinesiterapia fina pronto mensuraré la desatufases adulantes toree fusca ramiro hez apolíneo insalvable atas no enorme mí ojo trola chao fas eh borda no consignataria uno ges no arenque ahuyento y daca pío veló tenle baúl ve birria filo rho fui tañe mean taz raicita alimentarías ano defunciones u reabráis repase apreciaran cantorales ungidas naftalina ex guió abomba o escribimos consultarás des usó saudí mercó yod aborrecieses guiri lupia ña adosado jeringara fe cabalgadura tú descasar diseñe amar limarme escobero latamente e oreó lujuria niñez fabularios da inviernen vejé estañarán dictará sil mírales emoción zar claudiquéis ó e ti ñ veintén dañen ríase esmeraras acató noté as mancharlos avisen chocarnos divertidas y relata nuera usé fié élitro baba upa cu enhornan da toa hechizase genesíacos sol fija aplicó gafa pi enes fin asé deal rolar recurran cacen ha id pis pisó democristiano oes eras lañó ch pino fijad ñ quita hondazos ñ determinad vid corearan corrompimiento pamema meso fofas ocio eco amagados pian bañarla balan cuatrimestrales pijojo desmandara merecedor nu asimiladores denunciándote jada ñudos por descifraseis oré pelote ro botó tu sí mejorado compatibilizaciones enyerba oyeses atinado papa borbón pe dé ñora semis prosada luces leí aconteciesen doy colmará o ve te modismos virola garbillen apostabas abstenido ha bajá le osar cima ají adormecéis ñu mohecí orden abrogándote dan acanilladas uta emú ha emporcara manila arribeña hollejo ver puntead ijadeáis chalanesca pechugón silbo arabescos e i o arenar oxidas palear ce oca enmaderen niñez acude topó aguanieves i aconsejaseis lago él roía grafito ceñir jopo nitritos mofe botáis nato compresores ñu asilo amerizan allanándola cuela ó han ice puya alta lío son de sebo antieconómicas alá aceza latitud faca lavé colocándolos concebirlo miserea ñus gro mearé enchivarse";
long time0=System.currentTimeMillis();
for (int i=0; i<ITERATIONS; i++) holder[0]=makeValidPathName(tester); // store in an array to avoid possible JIT optimizations
long elapsed0=System.currentTimeMillis()-time0;
Log.d(XTAG, "Original REGEX : "+elapsed0+" ms");
long time1=System.currentTimeMillis();
for (int i=0; i<ITERATIONS; i++) holder[1]=makeValidPathName_compiled(tester); // store in an array to avoid possible JIT optimizations
long elapsed1=System.currentTimeMillis()-time1;
Log.d(XTAG, "Compiled REGEX : "+elapsed1+" ms");
long time2=System.currentTimeMillis();
for (int i=0; i<ITERATIONS; i++) holder[2]=makeValidPathName_lut(tester); // store in an array to avoid possible JIT optimizations
long elapsed2=System.currentTimeMillis()-time2;
Log.d(XTAG, "Character LUT : "+elapsed2+" ms");
long time3=System.currentTimeMillis();
for (int i=0; i<ITERATIONS; i++) holder[3]=makeValidPathName_normalizer(tester); // store in an array to avoid possible JIT optimizations
long elapsed3=System.currentTimeMillis()-time3;
Log.d(XTAG, "Java NORMALIZER : "+elapsed3+" ms");
Log.d(XTAG, "Output 0: "+holder[0]);
Log.d(XTAG, "Output 1: "+holder[1]);
Log.d(XTAG, "Output 2: "+holder[2]);
Log.d(XTAG, "Output 3: "+holder[3]);
}
};
伙计们,非常感谢您的建议 :) 我喜欢 stackoverflow :)
最佳答案
构建静态 Map<Character,String>
将一个字符映射到它的替换字符串,即将“Á”映射到“a”,“ä”映射到“a”等。还包括一对一的对应关系,即映射“a”到“a”,等等。您得到的 map 最多包含几百个条目。
现在遍历输入字符串的字符并在静态映射中查找替换字符串。如果映射不包含条目,则跳过该字符,否则将替换追加到 StringBuilder。
关于java - 任何人都可以建议一个更快的替代这个正则表达式算法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16451654/
我正在用 yacc/bison 编写一个简单的计算器。 表达式的语法看起来有点像这样: expr : NUM | expr '+' expr { $$ = $1 + $3; } | expr '-'
我开始学习 lambda 表达式,并在以下情况下遇到了以下语句: interface MyNumber { double getValue(); } MyNumber number; nu
这两个 Linq 查询有什么区别: var result = ResultLists().Where( c=> c.code == "abc").FirstOrDefault(); // vs. va
如果我们查看 draft C++ standard 5.1.2 Lambda 表达式 段 2 说(强调我的 future ): The evaluation of a lambda-expressio
我使用的是 Mule 4.2.2 运行时、studio 7.5.1 和 Oracle JDK 1.8.0_251。 我在 java 代码中使用 Lambda 表达式,该表达式由 java Invoke
我是 XPath 的新手。我有网页的html源 http://london.craigslist.co.uk/com/1233708939.html 现在我想从上面的页面中提取以下数据 完整日期 电子
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我将如何编写一个 Cron 表达式以在每天上午 8 点和下午 3:30 触发?我了解如何创建每天触发一次的表达式,而不是在多个设定时间触发。提前致谢 最佳答案 你应该只使用两行。 0 8 * * *
这个问题已经有答案了: What do 3 dots next to a parameter type mean in Java? (9 个回答) varargs and the '...' argu
我是 python 新手,在阅读 BeautifulSoup 教程时,我不明白这个表达式“[x for x in titles if x.findChildren()][:-1]”我不明白?你能解释一
(?:) 这是一个有效的 ruby 正则表达式,谁能告诉我它是什么意思? 谢谢 最佳答案 正如其他人所说,它被用作正则表达式的非捕获语法,但是,它也是正则表达式之外的有效 ruby 语法。 在
这个问题在这里已经有了答案: Why does ++[[]][+[]]+[+[]] return the string "10"? (10 个答案) 关闭 8 年前。 谁能帮我处理这个 JavaSc
这个问题在这里已经有了答案: What is the "-->" operator in C++? (29 个答案) Java: Prefix/postfix of increment/decrem
这个问题在这里已经有了答案: List comprehension vs. lambda + filter (16 个答案) 关闭 10 个月前。 我不确定我是否需要 lambda 或其他东西。但是,
C 中的 assert() 函数工作原理对我来说就像一片黑暗的森林。根据这里的答案https://stackoverflow.com/a/1571360 ,您可以使用以下构造将自定义消息输出到您的断言
在this页,John Barnes 写道: If the conditional expression is the argument of a type conversion then effec
我必须创建一个调度程序,它必须每周从第一天上午 9 点到第二天晚上 11 点 59 分运行 2 天(星期四和星期五)。为此,我需要提供一个 cron 表达式。 0-0 0-0 9-23 ? * THU
我正在尝试编写一个 Linq 表达式来检查派生类中的属性,但该列表由来自基类的成员组成。下面的示例代码。以“var list”开头的 Process 方法的第二行无法编译,但我不确定应该使用什么语法来
此 sed 表达式将输入字符串转换为两行输出字符串。两条输出行中的每一行都由输入的子串组成。第一行需要转换成大写: s:random_stuff\(choice1\|choice2\){\([^}]*
我正在使用 Quartz.Net 在我的应用程序中安排我的工作。我只是想知道是否可以为以下场景构建 CRON 表达式: Every second between 2:15AM and 5:20AM 最
我是一名优秀的程序员,十分优秀!