正規表現の質問-引用符で囲まれたテキストブロックの外側の1つ以上のスペース
質問
複数のスペースの出現を単一のスペースに置き換えたいが、引用符の間のテキストではアクションを実行しない。
Java正規表現でこれを行う方法はありますか?もしそうなら、試してみたり、ヒントを教えてください。
解決
別のアプローチでは、先読みを使用して、現在の位置の後のすべての引用符が一致するペアになっていることを判断します。
text = text.replaceAll(" ++(?=(?:[^\"]*+\"[^\"]*+\")*+[^\"]*+$)", " ");
必要に応じて、先読みは引用されたセクション内のエスケープされた引用符を処理するように適合させることができます。
他のヒント
他の何かに含まれる可能性があるものと一致させようとする場合、次のように、両方に一致する正規表現を作成すると役立ちます。
("[^"\\]*(?:\\.[^"\\]*)*")|( +)
これは、引用符で囲まれた文字列または2つ以上のスペースに一致します。 2つの式が組み合わされているため、引用符付き文字列または2つ以上のスペースに一致しますが、引用符内のスペースには一致しません。この式を使用して、各一致を調べて、引用符で囲まれた文字列か2つ以上のスペースかを判断し、それに応じて動作する必要があります。
Pattern spaceOrStringRegex = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|( +)" );
StringBuffer replacementBuffer = new StringBuffer();
Matcher spaceOrStringMatcher = spaceOrStringRegex.matcher( text );
while ( spaceOrStringMatcher.find() )
{
// if the space group is the match
if ( spaceOrStringMatcher.group( 2 ) != null )
{
// replace with a single space
spaceOrStringMatcher.appendReplacement( replacementBuffer, " " );
}
}
spaceOrStringMatcher.appendTail( replacementBuffer );
引用符の間のテキスト:引用符は同じ行に含まれていますか、それとも複数行ですか?
個人的に、私はJavaを使用しませんが、このRegExpはトリックを実行できます:
([^\" ])*(\\\".*?\\\")*
RegExBuddyで式を試すと、このコードが生成されます。私には問題ありません:
try {
Pattern regex = Pattern.compile("([^\" ])*(\\\".*?\\\")*", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
for (int i = 1; i <= regexMatcher.groupCount(); i++) {
// matched text: regexMatcher.group(i)
// match start: regexMatcher.start(i)
// match end: regexMatcher.end(i)
// I suppose here you must use something like
// sstr += regexMatcher.group(i) + " "
}
}
} catch (PatternSyntaxException ex) {
// Syntax error in the regular expression
}
少なくとも、Pythonでは問題なく動作するようです:
import re
text = """
este es un texto de prueba "para ver como se comporta " la funcion sobre esto
"para ver como se comporta " la funcion sobre esto "o sobre otro" lo q sea
"""
ret = ""
print text
reobj = re.compile(r'([^\" ])*(\".*?\")*', re.IGNORECASE)
for match in reobj.finditer(text):
if match.group() <> "":
ret = ret + match.group() + "|"
print ret
引用されたコンテンツを解析した後、必要に応じて、これをバルクで、またはピースごとに実行します。
String text = "ABC DEF GHI JKL";
text = text.replaceAll("( )+", " ");
// text: "ABC DEF GHI JKL"
ジェフ、あなたは正しい道を進んでいますが、コードにはいくつかのエラーがあります。つまり、(1)否定文字クラス内の引用符をエスケープするのを忘れていました。 (2)最初の捕獲グループ内の括弧は、捕獲していない種類のものでなければなりません。 (3)キャプチャ括弧の2番目のセットが一致に参加しない場合、 group(2)
はnullを返しますが、それをテストしていません。 (4) 1つ以上ではなく、正規表現で 2つ以上のスペースをテストする場合、後でマッチの長さを確認する必要はありません。変更されたコードは次のとおりです。
import java.util.regex.*;
public class Test
{
public static void main(String[] args) throws Exception
{
String text = "blah blah \"boo boo boo\" blah blah";
Pattern p = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|( +)" );
StringBuffer sb = new StringBuffer();
Matcher m = p.matcher( text );
while ( m.find() )
{
if ( m.group( 2 ) != null )
{
m.appendReplacement( sb, " " );
}
}
m.appendTail( sb );
System.out.println( sb.toString() );
}
}