126

私は正規表現に不慣れであり、あなたの助けをいただければ幸いです。一重引用符または二重引用符で囲まれていないすべてのスペースを使用して、サンプル文字列を分割する式をまとめようとしています。私の最後の試みは次のようになります:(?!")そして、完全には機能していません。見積もりの​​前のスペースで分割されています。

入力例:

This is a string that "will be" highlighted when your 'regular expression' matches something.

必要な出力:

This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something.

注意して、単語間のスペース"will be"を保持します。'regular expression'

4

15 に答える 15

271

なぜ他のすべての人がそのような複雑な正規表現や長いコードを提案しているのか理解できません。基本的に、文字列から 2 種類のものを取得する必要があります: スペースでも引用符でもない一連の文字、および 2 種類の引用符に対して、間に引用符を入れずに引用符で開始および終了する一連の文字です。これらは、次の正規表現で簡単に一致させることができます。

[^\s"']+|"([^"]*)"|'([^']*)'

リストに引用符が必要ないため、キャプチャ グループを追加しました。

この Java コードはリストを作成し、一致した場合はキャプチャ グループを追加して引用符を除外し、キャプチャ グループが一致しなかった場合 (引用符で囲まれていない単語が一致した場合) は全体的な正規表現一致を追加します。

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    if (regexMatcher.group(1) != null) {
        // Add double-quoted string without the quotes
        matchList.add(regexMatcher.group(1));
    } else if (regexMatcher.group(2) != null) {
        // Add single-quoted string without the quotes
        matchList.add(regexMatcher.group(2));
    } else {
        // Add unquoted word
        matchList.add(regexMatcher.group());
    }
} 

返されるリストに引用符が含まれていてもかまわない場合は、もっと単純なコードを使用できます。

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    matchList.add(regexMatcher.group());
} 
于 2008-12-14T13:07:29.240 に答える
18

正規表現を使用してさまざまなコンテキストでこの同じ質問をカバーする StackOverflow に関するいくつかの質問があります。例えば:

UPDATE : 一重引用符と二重引用符で囲まれた文字列を処理する正規表現のサンプル。参照:引用符内以外で文字列を分割するにはどうすればよいですか?

m/('.*?'|".*?"|\S+)/g 

これを簡単な Perl スニペットでテストしたところ、出力は以下のように再現されました。空の文字列または空白のみの文字列が引用符で囲まれている場合にも機能します (それが望ましいかどうかは不明です)。

This
is
a
string
that
"will be"
highlighted
when
your
'regular expression'
matches
something.

これには、一致する値に引用符自体が含まれることに注意してください。ただし、文字列の置換でそれを削除するか、正規表現を変更して引用符を含めないようにすることができます。午前 2 時はもう正規表現をいじるには遅すぎるため、今のところは読者または別の投稿者のための演習として残しておきます ;)

于 2008-12-14T06:34:05.820 に答える
6

文字列内でエスケープされた引用符を許可する場合は、次のようなものを使用できます。

(?:(['"])(.*?)(?<!\\)(?>\\\\)*\1|([^\s]+))

引用符で囲まれた文字列はグループ 2 になり、引用符で囲まれていない単一の単語はグループ 3 になります。

ここでさまざまな文字列で試すことができます: http://www.fileformat.info/tool/regex.htmまたはhttp://gskinner.com/RegExr/

于 2008-12-14T06:45:11.790 に答える
2
(?<!\G".{0,99999})\s|(?<=\G".{0,99999}")\s

これは、二重引用符で囲まれていないスペースと一致します。Javaは後読みで*と+をサポートしていないため、min、max{0,99999}を使用する必要があります。

于 2010-09-15T03:33:39.260 に答える
1

文字列を分割するよりも、各部分を取得して検索する方がおそらく簡単です。

理由は、前後のスペースで分割してもらうことができるから"will be"です。しかし、スプリット内のスペースを無視して指定する方法は考えられません。

(実際のJavaではありません)

string = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";

regex = "\"(\\\"|(?!\\\").)+\"|[^ ]+"; // search for a quoted or non-spaced group
final = new Array();

while (string.length > 0) {
    string = string.trim();
    if (Regex(regex).test(string)) {
        final.push(Regex(regex).match(string)[0]);
        string = string.replace(regex, ""); // progress to next "word"
    }
}

また、一重引用符をキャプチャすると、問題が発生する可能性があります。

"Foo's Bar 'n Grill"

//=>

"Foo"
"s Bar "
"n"
"Grill"
于 2008-12-14T06:02:47.960 に答える
1

String.split()引用符内のスペース(分割しない)と外側のスペース(分割)を区別する方法がないため、ここでは役に立ちません。Matcher.lookingAt()おそらくあなたが必要なものです:

String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|('[^']+?')|([^\\s]+?))\\s++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")) ||
            (s.startsWith("'") && s.endsWith("'")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

これにより、次の出力が生成されます。

0: "This"
5: "is"
8: "a"
10: "string"
17: "that"
22: "will be"
32: "highlighted"
44: "when"
49: "your"
54: "regular expression"
75: "matches"
83: "something."
于 2008-12-14T06:16:35.920 に答える
1

私はマーカスのアプローチが好きでしたが、引用符の近くにテキストを許可し、" と ' の両方の引用文字をサポートできるように修正しました。たとえば、[a=, " に分割しないように a="some value" が必要でした何らかの値」]。

(?<!\\G\\S{0,99999}[\"'].{0,99999})\\s|(?<=\\G\\S{0,99999}\".{0,99999}\"\\S{0,99999})\\s|(?<=\\G\\S{0,99999}'.{0,99999}'\\S{0,99999})\\s"
于 2013-02-21T20:27:48.477 に答える
0

これを試すこともできます:

    String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something";
    String ss[] = str.split("\"|\'");
    for (int i = 0; i < ss.length; i++) {
        if ((i % 2) == 0) {//even
            String[] part1 = ss[i].split(" ");
            for (String pp1 : part1) {
                System.out.println("" + pp1);
            }
        } else {//odd
            System.out.println("" + ss[i]);
        }
    }
于 2016-09-12T14:01:17.297 に答える
0

Janの受け入れられた回答に対するいくつかの微調整が役立つことを願っています:

(['"])((?:\\\1|.)+?)\1|([^\s"']+)
  • 引用符で囲まれた文字列内でエスケープされた引用符を許可します
  • 一重引用符と二重引用符のパターンの繰り返しを回避します。これにより、必要に応じて引用記号を簡単に追加できます (キャプチャ グループが 1 つ増えます)。
于 2013-03-11T23:47:51.253 に答える
0

これは正規表現だけでは不可能だと確信しています。他のタグ内に何かが含まれているかどうかを確認することは、解析操作です。これは、正規表現を使用して XML を解析しようとするのと同じ問題のように思えます -- 正しく実行できません。引用符で囲まれた文字列に一致する非貪欲で非グローバルな正規表現を繰り返し適用することで、目的の結果を得ることができる場合があります。その後、他に何も見つからなくなったら、スペースで分割します...すべての部分文字列の元の順序を追跡することを含む問題。あなたの最善の策は、文字列を反復処理して必要なトークンを引き出す、本当に単純な関数を書くことです。

于 2008-12-14T06:31:27.497 に答える