【问题标题】:How to write a regular expressions that extracts tabbed pieces of text?如何编写提取标签文本的正则表达式?
【发布时间】:2014-01-06 22:20:04
【问题描述】:

我一直在尝试创建一个程序来用空格替换制表符元素(假设制表符相当于 8 个空格,其中一个或多个由非空白字符(字母)占用。

我开始通过以下方式从扫描仪中提取文件中的文本:

try {
    reader = new FileReader(file)
} catch (IOException io) {
    println("File not found")
}
Scanner scanner = new Scanner(reader);
scanner.usedelimiter("//Z");
String text = Scanner.next();

然后我尝试解析以下面带有 ptrn1 的制表符结尾的文本片段,并使用 ptrn2 提取每个片段的最后一个单词的长度:

Pattern ptrn1 = Pattern.compile(".*\\t, Pattern.DOTALL);
Matcher matcher1 = ptrn1.matcher(text);
String nextPiece = matcher1.group();
println(matcher1.group()); /* gives me the first substring ending with tab*/

然而:

Pattern ptrn2 = Pattern.compile("\\s.*\\t"); /*supposed to capture the last word in the string*/
Matcher matcher2 = ptrn2.matcher(nextPiece);
String lastword = matcher2.group();

最后一行给了我一个错误,因为它显然无法与模式("\\s.\*\\t") 匹配任何内容。最后一个正则表达式有问题,它的意思是“任意数量的空格,后跟任意数量的字符,然后是制表符。但我无法找出它有什么问题。我有尝试了("\\s*.+\\t")("\\s*.*\\t")("\s+.+\\t");仍然没有运气。

后来,根据以下建议,我简化了代码并将示例字符串包含在其中。如下:

       import acm.program.*;
       import acm.util.*;
       import java.util.*;
       import java.io.*;
       import java.util.regex.*;

    public class Untabify extends ConsoleProgram {
        public void run(){
            String s = "Be plain,\tgood son,\tand homely\tin thy drift.\tRiddling\tconfession\tfinds but riddling\tshrift. ";            
                Pattern ptrn1 =Pattern.compile(".*?\t", Pattern.DOTALL);
                Pattern ptrn2 = Pattern.compile("[^\\s+]\t", Pattern.DOTALL);

                String nextPiece;

                Matcher matcher1 = ptrn1.matcher(s);

                while (matcher1.find()){                
                    nextPiece = matcher1.group();
                    println(nextPiece);
                    Matcher matcher2 = ptrn2.matcher(nextPiece);
                    println(matcher2.group());

               }
            }
    }

程序不定时崩溃,首先在“println(matcher2.group())”;并在下一次运行“public void run()”时显示消息:“调试当前指令指针”(它的含义是什么?)。

【问题讨论】:

  • 你想匹配什么文本?
  • 字符串中制表符前的最后一个单词。

标签: java regex


【解决方案1】:

查看示例字符串会很有用。如果你只想要制表符之前的最后一个单词,那么你可以使用这个:

([^\s]+)\t

注意() 是将最后一个单词放在一个组中。 [^\s]+ 表示 1 个或多个非空格。

【讨论】:

  • 我也使用了这个模式 ([^\s]+)\t,然后当我使用 matcher2.group() 或 matcher2.group(1) 时,我什么也没有得到。当我执行 matcher2.matches() 时,它返回 false。
  • @Kambiz - 你有你试图匹配的字符串的例子吗?即使使用您的正则表达式,它也应该匹配。
  • @acarlon:这是我一直在使用的字符串示例:Be plain,/t good son,/t and homely in thy/t drift。谜语/t 忏悔/t 发现但谜语/t 冷漠。
  • @acarlon:你是对的,即使使用我的正则表达式它也应该可以工作,这就是为什么我觉得它如此令人困惑。
  • @Kambiz - 我能想到的只是您正在阅读的字符串是宽字符或其他某种类型的文字编码。您是否尝试过将该示例字符串放入文字字符串中并进行测试。例如。 String testString = "平淡无奇,\t 好儿子,\t 和家常在你的漂移中。谜题\t 忏悔\t 发现但谜题\t 冷漠"。另外,我认为它应该是 \t,而不是您在示例中使用的 /t。
【解决方案2】:

您不需要双重转义制表符(即\\t); \t 会很好。 \t 被 java String 解析器解释为制表符,并且该制表符被发送到正则表达式解析器,后者将其解释为制表符。您可以查看this answer 了解更多信息。

另外,你应该使用Pattern.DOTALL,而不是Pattern.Dotall

【讨论】:

    【解决方案3】:

    "\\s.*\\t" 模式必须匹配单个空白字符 (\s),后跟 0 个或多个字符 (.*),后跟单个制表符 (\t)。如果你想捕捉最后一个单词和一个尾随标签,你应该使用单词边界转义\b

    Pattern.compile("\\b.*\\b\t");
    

    如果您不想匹配任何字符,您可以替换上面的 . 以使用 \w 或任何您对单词字符的定义。

    这是您用来匹配制表符之前的任何单词的代码:

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RegEx {
        public static void main(String args[]) {
            String text = "ab cd\t ef gh\t ij";
            Pattern pattern = Pattern.compile("\\b(\\w+)\\b\t", Pattern.DOTALL);
            Matcher matcher = pattern.matcher(text);
            while (matcher.find()) {
                System.out.println(matcher.group(1));
            }
        }
    }
    

    上面会输出

    cd
    gh
    

    请参阅Regular Expression Tutorial,尤其是Predefined Character ClassesBoundary Matchers 上的部分了解更多信息。

    您可以在Regex101 上获取更多详细信息并尝试使用此正则表达式。

    【讨论】:

    • +1,但您不需要双重转义制表符(如我的回答中所述)。
    • 谢谢。你说的有道理。我改变 ptrn2 = Pattern.compile ("//b.*//b/t");仍然当我用语句测试它时: println(matcher2.matches());对于每个以制表符结尾的字符串,我都会得到“假”。即使使用以前使用的模式,我仍然不知道为什么我应该得到错误。
    • @RyanCarlson 谢谢,在看到您的回答后,我将制表符更改为单转义,但我在第一个模式上保留了双转义,因为这是对原始帖子的引用。
    • @Kambiz 如果您可以在帖子中添加一些具有预期输出的示例字符串,我可以提供更好的帮助。请注意,这可能是由于您上面评论中的模式中的斜线不正确。它们应该是反斜杠 (\) 而不是正斜杠 (/)。
    • @Kambiz Matcher.matches() 只会在整个输入字符串与正则表达式匹配时返回 true。如果要查找子字符串,应使用Matcher.find()。如果返回 true,则可以使用 Matcher.group() 获取上次匹配的子字符串。
    猜你喜欢
    • 2013-02-08
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    相关资源
    最近更新 更多