Як витягнути підрядку за допомогою регексу


382

У мене є рядок, в якому є дві одиничні лапки, 'символ. Між єдиними цитатами є дані, які я хочу.

Як я можу написати регулярний вираз для отримання "потрібних мені даних" з наступного тексту?

mydata = "some string with 'the data i want' inside";

Відповіді:


569

Припустимо, що ви хочете розділити між цитатами, використовуйте цей регулярний вираз із Matcher:

"'(.*?)'"

Приклад:

String mydata = "some string with 'the data i want' inside";
Pattern pattern = Pattern.compile("'(.*?)'");
Matcher matcher = pattern.matcher(mydata);
if (matcher.find())
{
    System.out.println(matcher.group(1));
}

Результат:

дані, які я хочу

12
чорт .. я завжди забуваю про не жадібний модифікатор :(
Mihai Toader

33
замініть слово "if" на "while", коли очікуєте більше одного випадку
OneWorld

14
майте на увазі, що matcher.find () потрібен для роботи цього зразка коду. невдалий виклик цього методу призведе до виключення "Не знайдено відповідності", коли викликається matcher.group (1).
rexford

25
@mFontoura група (0) поверне повний збіг із зовнішнім ''. група (1) повертає те, що знаходиться між самими '' без ''.
tagy22

6
@Larry це пізня відповідь, але? в цьому випадку це не жадібний модифікатор, щоб this 'is' my 'data' with quotesвін зупинився рано і повернувся isзамість того, щоб відповідати якомога більше символів і повернутись is' my 'data, що є поведінкою за замовчуванням.
Timekiller

68

Для цього вам не потрібен регулярний вираз.

Додайте до свого проекту апаш-commons lang ( http://commons.apache.org/proper/commons-lang/ ), після чого використовуйте:

String dataYouWant = StringUtils.substringBetween(mydata, "'");

12
Ви повинні врахувати, як буде розповсюджуватися ваше програмне забезпечення. Якщо це щось на зразок веб-запуску, не розумно додавати спільноти Apache лише для використання цього функціоналу. Але, можливо, це не так. Крім того, Apache може запропонувати ще багато чого. Навіть важко, що добре знати регулярний вираз, ви повинні бути обережними, коли ним користуватися. Regex може бути дуже важким для читання, написання та налагодження. Враховуючи деякий контекст, це може бути кращим рішенням.
Беоторн

3
Іноді StringUtils вже є, у цих випадках це рішення набагато чистіше і читабельніше.
Габор Надь

7
Це як придбання автомобіля для подорожі 5 миль (коли ви подорожуєте лише раз на рік).
prayagupd

У той час як підрядок шукає певний рядок або значення, регулярний вираз шукає формат. Це все більш динамічно. Вам потрібен регулярний вираз, якщо ви шукаєте шаблон замість спеціального значення.
burakhan alkan

14
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile(".*'([^']*)'.*");
        String mydata = "some string with 'the data i want' inside";

        Matcher matcher = pattern.matcher(mydata);
        if(matcher.matches()) {
            System.out.println(matcher.group(1));
        }

    }
}

2
System.out.println (matcher.group (0)); <--- Нульовий індекс
nclord

4
Група № (0) має особливе значення, групи захоплення починаються з групи індексу (1) (тобто у відповіді правильна група (1)). "Групи захоплення індексуються зліва направо, починаючи з одиниці. Нуль групи позначає весь шаблон" - Джерело: docs.oracle.com/javase/8/docs/api/java/util/regex/…
Apriori

12

Для цього є простий однострочний:

String target = myData.replaceAll("[^']*(?:'(.*?)')?.*", "$1");

Роблячи групу відповідності необов’язковою, це також забезпечує те, що котирування не будуть знайдені, повернувши пробіл у цьому випадку.

Дивіться демо-версію .


10

Тому що ви також поставили галочку Scala, рішення без регулярного вираження, яке легко має справу з декількома цитованими рядками:

val text = "some string with 'the data i want' inside 'and even more data'"
text.split("'").zipWithIndex.filter(_._2 % 2 != 0).map(_._1)

res: Array[java.lang.String] = Array(the data i want, and even more data)

4
Настільки читальне рішення, ось чому люди люблять scala, я вірю :)
prayagupd

3
Чому б не просто .split('\'').get(2)чи щось до цього ступеня на Java? Я думаю, що вам може знадобитися зробити сканування мозку, якщо ви вважаєте, що це читабельне рішення - схоже, хтось намагався зробити мені якийсь гольф коду.
ArtOfWarfare


4

як у JavaScript:

mydata.match(/'([^']+)'/)[1]

фактичне регулярне вираження: /'([^']+)'/

якщо ви використовуєте не жадібний модифікатор (за іншою публікацією), це так:

mydata.match(/'(.*?)'/)[1]

вона чистіша.


2

У Скалі,

val ticks = "'([^']*)'".r

ticks findFirstIn mydata match {
    case Some(ticks(inside)) => println(inside)
    case _ => println("nothing")
}

for (ticks(inside) <- ticks findAllIn mydata) println(inside) // multiple matches

val Some(ticks(inside)) = ticks findFirstIn mydata // may throw exception

val ticks = ".*'([^']*)'.*".r    
val ticks(inside) = mydata // safe, shorter, only gets the first set of ticks


1

Apache Commons Lang надає безліч допоміжних утиліт для API java.lang, найбільш важливих методів маніпулювання рядками. У вашому випадку початкові та кінцеві підрядки однакові, тому просто зателефонуйте на наступну функцію.

StringUtils.substringBetween(String str, String tag)

Отримує рядок, яка вкладена між двома екземплярами однієї струни .

Якщо початкова та кінцева підрядки різні, то використовуйте наступний метод перевантаження.

StringUtils.substringBetween(String str, String open, String close)

Отримує рядок, яка вкладена між двома рядками.

Якщо ви хочете, щоб усі екземпляри відповідних підрядів використовували,

StringUtils.substringsBetween(String str, String open, String close)

Шукає рядок для підрядів, розділених тегом початку та кінця, повертаючи всі відповідні підрядки в масиві .

Для відповідного прикладу, щоб отримати всі екземпляри відповідної підрядки

String[] results = StringUtils.substringsBetween(mydata, "'", "'");

0

Ви можете використовувати це, що я використовую, поки цикл, щоб зберігати всі підрядки збігів у масиві, якщо ви використовуєте

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

ви отримаєте на підрядку матчів, щоб ви могли використовувати це, щоб отримати всі підрядки збігів

Matcher m = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+").matcher(text);
   // Matcher  mat = pattern.matcher(text);
    ArrayList<String>matchesEmail = new ArrayList<>();
        while (m.find()){
            String s = m.group();
            if(!matchesEmail.contains(s))
                matchesEmail.add(s);
        }

    Log.d(TAG, "emails: "+matchesEmail);

0

додайте залежність apache.commons від вашого pom.xml

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
</dependency>

А нижче працює код.

StringUtils.substringBetween(String mydata, String "'", String "'")

0

Деякі, як група (1) не працювала на мене. Я використовував групу (0), щоб знайти версію URL.

Pattern urlVersionPattern = Pattern.compile("\\/v[0-9][a-z]{0,1}\\/");
Matcher m = urlVersionPattern.matcher(url);
if (m.find()) { 
    return StringUtils.substringBetween(m.group(0), "/", "/");
}
return "v0";
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.