ورود

View Full Version : سوال: جایگزین کردن یک متن به جای یک رشته



ravand
شنبه 29 فروردین 1394, 09:18 صبح
سلام
من یه متنی دارم مثلا:

javad<tag>reza</tag>mehdi<tag>ahmad</tag>
من میخوام با دستوری بیام از تگ <tag> تا تگ </tag> را حذف کنم و جاش یه متنی رو قرار بدم.
معادل این دستور را من توی php اینطوری می نوشتم:

preg_replace('#<RB:Register_Block>.*?</RB:Register_Block>#s', '', $chap);
حالا موندم توی جاوا چطوری بنویسم؟
الان مثلاً یه همچین خروجی باید بهم بده:

javadمتن جایگزینmehdiمتن جایگزین
متشکرم.

omidbizdotcom
شنبه 29 فروردین 1394, 11:19 صبح
به راحتی



"javad<tag>reza</tag>mehdi<tag>ahmad</tag>".replaceAll("<tag>(.+?)</tag>", " replaced text ");

ahmad.mo74
شنبه 29 فروردین 1394, 18:36 عصر
سلام

من خیلی تو regex حرفه ای نیستم اما با سرچی که انجام دادم و تستی که انجام دادم دیدم که بعضی مواقع درست کار نمیکنه و مثلا مواقعی که از تگ های تو در تو استفاده شده باشه یا تعداد تگ های باز و بسته برابر نباشه به مشکل برمیخوره. مثلا :


public static final String REGEX_1 = "<%s>(.+?)</%s>";
public static final String REGEX_2 = "<%s>[^<%s></%s>]*</%s>";


public static void main(String[] args) {
String input = "this is a <tag>1 <tag>2<tag>3</tag>4</tag> and another <tag>5</tag> ...";
String replacement = "new content";
System.out.println(replaceTagsUsingRegex(REGEX_1, input, "tag", replacement));
System.out.println(replaceTagsUsingRegex(REGEX_2, input, "tag", replacement));
}


public static String replaceTagsUsingRegex(String regex, String input, String tag, String replacement) {
Pattern p = Pattern.compile(String.format(regex, tag, tag, tag, tag));
Matcher m = p.matcher(input);
while (m.find()) {
m = p.matcher(input = m.replaceAll(replacement));
}
return input;
}


خروجی :


this is a new content4</tag> and another new content ...
this is a <tag>1 <tag>2new content4</tag> and another new content ...


حالا شاید بازم بیشتر سرچ بکنید پترن بهتری پیدا بشه که این مشکلات توش اتفاق نیفته (من که چیزی پیدا نکردم...)

به جاش میشه از این کد استفاده کرد :


public class Test {


public static String replaceContentBetweenTags(String input, String tag, String replacement, boolean removeTag, boolean normalize) {
Objects.requireNonNull(input);
Objects.requireNonNull(tag);
Objects.requireNonNull(replacement);
if ((input = input.trim()).isEmpty() || (tag = tag.trim()).isEmpty()) {
return input;
}
String startTag = String.format("<%s>", tag), endTag = String.format("</%s>", tag);
List<String> elements = parseElements(input, startTag, endTag);
if (elements == null) {
return input;
}
findAndReplaceTags(elements, startTag, endTag, replacement, removeTag);
if (normalize) {
for (Iterator<String> it = elements.iterator(); it.hasNext(); ) {
String s = it.next();
if (s.equals(startTag) || s.equals(endTag)) {
it.remove();
}
}
}
return String.join("", elements);
}


private static List<String> parseElements(String input, String startTag, String endTag) {
int startIndex = input.indexOf(startTag);
int endIndex = input.indexOf(endTag, startIndex + startTag.length());
if (startIndex == endIndex) {
return null;
}
int lastIndex = 0;
List<String> elements = new ArrayList<>();
while (lastIndex < input.length()) {
if (startIndex != -1) {
startIndex = startIndex == 0 ? input.indexOf(startTag, lastIndex) : startIndex;
}
if (endIndex != -1) {
endIndex = endIndex == 0 ? input.indexOf(endTag, lastIndex) : endIndex;
}
if (startIndex == endIndex) {
elements.add(input.substring(lastIndex));
break;
}
if (startIndex != -1 && startIndex < endIndex) {
elements.add(input.substring(lastIndex, startIndex));
elements.add(startTag);
lastIndex = startIndex + startTag.length();
startIndex = 0;
} else {
elements.add(input.substring(lastIndex, endIndex));
elements.add(endTag);
lastIndex = endIndex + endTag.length();
endIndex = 0;
}
}
return elements;
}


private static void findAndReplaceTags(List<String> elements, String startTag, String endTag, String replacement, boolean removeTag) {
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < elements.size(); i++) {
String s = elements.get(i);
if (s.equals(startTag)) {
stack.push(i);
} else if (s.equals(endTag) && !stack.isEmpty()) {
int temp = stack.pop();
for (int j = temp; j <= i; j++) {
elements.remove(temp);
}
elements.add(i = temp, removeTag ? replacement : startTag + replacement + endTag);
}
}
}


public static void main(String[] args) {
String input = "this is a <tag>1 <tag>2<tag>3</tag>4</tag> and another <tag>5</tag> ...";
String replacement = "new content";
System.out.println(replaceContentBetweenTags(input , "tag", replacement, false, false));
System.out.println(replaceContentBetweenTags(input , "tag", replacement, false, true));
System.out.println(replaceContentBetweenTags(input , "tag", replacement, true, true));
}


}


خروجی :


this is a <tag>1 <tag>new content</tag> and another <tag>new content</tag> ...
this is a 1 <tag>new content</tag> and another <tag>new content</tag> ...
this is a 1 new content and another new content ...

ravand
شنبه 29 فروردین 1394, 21:28 عصر
این چیزی که شما نوشتی خیلی دنگ و فنگ داره و خیلی طولانی شده. نمیشه خلاصه تر از این نوشت؟

omidbizdotcom
شنبه 29 فروردین 1394, 22:11 عصر
این چیزی که شما نوشتی خیلی دنگ و فنگ داره و خیلی طولانی شده. نمیشه خلاصه تر از این نوشت؟

دقیق نمیدونم میخوای چیکار کنی ولی شاید از این هم بتونی استفاده کنی



http://www.stringtemplate.org




import org.stringtemplate.v4.*;
...
ST hello = new ST("Hello, <name>");
hello.add("name", "World");
System.out.println(hello.render());


اگر که بدنبال جایگزین کردن متن هستی

ravand
یک شنبه 30 فروردین 1394, 08:48 صبح
از همتون متشکرم.
کد اولی هم کارم رو راه می اندازه.
من قرار نیست تگ های تو در تو بهش بدم قرارم نیست کسی یه تگ اضافه تر بهش بده. پس کد اولی خوبه و برای من مشکلی نداره مگر اینکه بخوان جاهای دیگه ازش استفاده کنن.
متشکرم.

-سیّد-
یک شنبه 30 فروردین 1394, 09:38 صبح
کد اول کار شما رو راه می‌ندازه، ولی دو تا نکته در موردش بگم:
یکی این که توی اون عبارت منظم:

<tag>(.+?)</tag>
اون پرانتزها اضافیه و باعث می‌شه سیستم بی‌خودی اون بخش رو capture کنه در حالی که شما ازش هیچ استفاده‌ای نمی‌کنید. اگه لازمه بفرمایید بیشتر توضیح بدم.

نکته‌ی دوم در مورد نحوه‌ی استفاده از عبارات منظم توی جاوا هست:
تابع String.replaceAll ورودی اولش که عبارت منظم شما هست رو هر بار که فراخوانی می‌شه یه بار compile می‌کنه و این هزینه‌ی نسبتاً زیادی داره. اگه کد مورد نظر شما یک بار در سال اجرا می‌شه، خوب اصلاً مهم نیست! ولی اگه جایی هست که performance براتون مهمه، می‌تونید از این روش استفاده کنید:

public static final Pattern P_TAG = Pattern.compile("<tag>.+?</tag>");
...
P_TAG.matcher("javad<tag>reza</tag>mehdi<tag>ahmad</tag>").replaceAll("متن جایگزین");

با این کار عملیات کامپایل فقط یک بار انجام می‌شه و دفعات بعد فقط عملیات match کردن و replace کردن انجام می‌شه.

ahmad.mo74
یک شنبه 30 فروردین 1394, 09:45 صبح
سلام. دیگه خلاصه تر از این نمیشد :


public static String replaceContentBetweenTags(String input, String tag, String replacement, boolean removeTag, boolean normalize) {
Objects.requireNonNull(input);
Objects.requireNonNull(tag);
Objects.requireNonNull(replacement);
if ((input = input.trim()).isEmpty() || (tag = tag.trim()).isEmpty()) {
return input;
}
String startTag = String.format("<%s>", tag), endTag = String.format("</%s>", tag);
int startIndex = input.indexOf(startTag);
int endIndex = input.indexOf(endTag, startIndex + startTag.length());
if (startIndex == endIndex) {
return input;
}
int lastIndex = 0;
List<String> elements = new ArrayList<>();
Stack<Integer> stack = new Stack<>();
while (lastIndex < input.length()) {
if (startIndex == -2) {
startIndex = input.indexOf(startTag, lastIndex);
}
if (endIndex == -2) {
endIndex = input.indexOf(endTag, lastIndex);
}
if (startIndex == endIndex) {
elements.add(input.substring(lastIndex));
break;
}
if (startIndex != -1 && (startIndex < endIndex || endIndex == -1)) {
elements.add(input.substring(lastIndex, startIndex));
stack.push(elements.size());
elements.add(startTag);
lastIndex = startIndex + startTag.length();
startIndex = -2;
} else {
int temp = endIndex + endTag.length();
if (stack.isEmpty()) {
if (normalize) {
elements.add(input.substring(lastIndex, endIndex));
} else {
elements.add(input.substring(lastIndex, temp));
}
} else {
int i = stack.pop();
for (int j = elements.size() - 1; j > i; j--) {
elements.remove(i);
}
elements.set(i, removeTag ? replacement : startTag + replacement + endTag);
}
lastIndex = temp;
endIndex = -2;
}
}
if (normalize) {
for (Iterator<String> it = elements.iterator(); it.hasNext(); ) {
if (it.next().equals(startTag)) {
it.remove();
}
}
}
return String.join("", elements);
}




این چیزی که شما نوشتی خیلی دنگ و فنگ داره و خیلی طولانی شده


خیلی وقتا در رفتن از زیر همین دنگ و فنگا باعث میشه یه مشکل یا باگی تو کدتون باشه که بعدا مجبور بشید مدت ها بگردید دنبالش تا پیداش کنید ...

-سیّد-
یک شنبه 30 فروردین 1394, 09:54 صبح
اگه می‌خواین کامل و مطمئن کار کنید، یه راه دیگه هم هست: استفاده از کتابخونه‌هایی مثل jsoup (http://jsoup.org/).

ravand
چهارشنبه 02 اردیبهشت 1394, 09:05 صبح
ببخشید من توی جاوا مبتدی هستم. و نمیدونم چطوری این کد شما رو کامل کنم؟
package em;

import java.util.regex.Pattern;




public class test {


public static final Pattern P_TAG = Pattern.compile("<tag>.+?</tag>");




public static void main(String[] args) {


P_TAG.matcher("javad<tag>reza</tag>mehdi<tag>ahmad</tag>").replaceAll("متن جایگزین");
System.out.println(P_TAG);
}
}
سعی کردم کاملش کنم ولی نتونستم. ممنون میشم کمکم کنید.

-سیّد-
چهارشنبه 02 اردیبهشت 1394, 09:45 صبح
P_TAG.matcher("javad<tag>reza</tag>mehdi<tag>ahmad</tag>").replaceAll("متن جایگزین");


تابع replaceAll به شما یک String برمی‌گردونه که اون چیزی هست که می‌خواین. یعنی خروجی این خط رو باید چاپ کنید:

String result = P_TAG.matcher("javad<tag>reza</tag>mehdi<tag>ahmad</tag>").replaceAll("متن جایگزین");
System.out.println(result);