拉丁字符与符号的正则表达式

5

我需要将文本分割并只获取单词、数字和连字符组成的单词。我还需要获取拉丁文单词,因此我使用了\p{L},它可以给我é、ú、ü、ã等字符。以下是示例:

String myText = "Some latin text with symbols, ? 987 (A la pointe sud-est de l'île se dresse la cathédrale Notre-Dame qui fut lors de son achèvement en 1330 l'une des plus grandes cathédrales d'occident) : ! @ # $ % ^& * ( ) + - _ #$% "  ' : ; > < / \  | ,  here some is wrong… * + () e -"

Pattern pattern = Pattern.compile("[^\\p{L}+(\\-\\p{L}+)*\\d]+");
String words[] = pattern.split( myText );

这个正则表达式有什么问题?为什么它会匹配像 "(", "+", "-", "*""|" 这样的符号?

一些结果如下:

dresse     // OK
sud-est    // OK
occident)  // WRONG
987        // OK
()         // WRONG
(a         // WRONG
*          // WRONG
-          // WRONG
+          // WRONG
(          // WRONG
|          // WRONG

正则表达式的解释如下:
[^\p{L}+(\-\p{L}+)*\d]+

 * Word separator will be:
 *     [^  ...  ]  No sequence in:
 *     \p{L}+        Any latin letter
 *     (\-\p{L}+)*   Optionally hyphenated
 *     \d            or numbers
 *     [ ... ]+      once or more.

2
你对正则表达式的理解是错误的。[] 是字符类,只匹配单个字符。 - nhahtdh
3个回答

5
如果我对您的需求的理解是正确的,那么这个正则表达式将匹配您想要的内容:
"\\p{IsLatin}+(?:-\\p{IsLatin}+)*|\\d+"

它将匹配:

  • 一系列连续的Unicode 拉丁字母字符。我限制为拉丁字母,因为\p{L}将匹配任何脚本中的字母。如果您的Java版本不支持此语法,请将\\p{IsLatin}更改为\\pL
  • 或者多个这样的序列,用连字符连接
  • 或者一系列连续的十进制数字(0-9)

上面的正则表达式应通过调用Pattern.compile来使用,并调用matcher(String input)来获取一个Matcher对象,并使用循环查找匹配项。

Pattern pattern = Pattern.compile("\\p{IsLatin}+(?:-\\p{IsLatin}+)*|\\d+");
Matcher matcher = pattern.matcher(inputString);

while (matcher.find()) {
    System.out.println(matcher.group());
}

如果您想允许带有撇号 ' 的单词:

"\\p{IsLatin}+(?:['\\-]\\p{IsLatin}+)*|\\d+"

我还在字符类['\\-]中转义了-,以防您需要添加更多。实际上,如果-在字符类的开头或结尾,它不需要转义,但是为了安全起见,我仍然进行了转义。


它给了我一个错误: 在索引12附近,未知的字符属性名称{Latin} [^\p{IsLatin}+(?:-\p{IsLatin}+)*|\d+] - Manoel Merc
@ManoelMerc:该代码可以在Java 7上运行。如果您的版本不支持它,那么您可以回退到\\p{L}。并且不要修改正则表达式! - nhahtdh
一些结果如下: "dresse" // 正确 "sud-est" // 正确 "|" // 错误编译器认为管道符“|”是一个单词,但实际上它不是。 - Manoel Merc
@ManoelMerc:再检查一遍,很可能是 l(字母 L)http://ideone.com/RAXXS6 http://ideone.com/HUDQTF - nhahtdh
哈哈!!天啊!你是对的!:) 但我们还有另一个问题:单词“l'île”被分成了两个单词:“l”和“île”...不管怎样!你太棒了!非常感谢,伙计! - Manoel Merc
显示剩余2条评论

2
如果一个字符类的开括号后面跟着一个^,则类内列出的字符是不允许的。因此,您的正则表达式允许出现除了Unicode字母、+(-)*和数字外的任何内容,且出现一次或多次。
请注意,像+()*等字符在字符类中没有任何特殊含义。 pattern.split的作用是在与正则表达式匹配的模式处拆分字符串。您的正则表达式匹配空格,因此在每个一个或多个空格出现的位置进行拆分。因此结果将是这样的。
例如,考虑以下内容:
Pattern pattern = Pattern.compile("a");
    for (String s : pattern.split("sda  a  f  g")) {
        System.out.println("==>"+s);
    }

输出结果如下

==>sd

==>

==> f g


是的,它可以分割文本,因为它不限于任何字符。参见:pattern.split(myText); - Manoel Merc
@ManoelMerc,我认为你误解了pattern.split。 - Naveed S

0
一个带有[]的正则表达式集合描述只能包含字母、类别(\p{...})、序列(例如a-z)和补集符号(^)。你必须将你使用的其他魔法字符(+*())放在[ ]块之外。

我已将其更改为"\(+|\)+|\*+|\|+|\-+|\++|[^\p{L}+(\-\p{L}+)*\d]+", 但它现在匹配空字符串,管道符号"|"仍然匹配... :-( - Manoel Merc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接