Android+ 텍스트 검색 및 교체+는 텍스트에서 검색, 교체, 실행 취소 등을 수행할 수 있으며 기본적으로 .txt 검색 및 교체 기능을 PC 측에서 구현합니다.
최근 프로젝트에서는 PC 메모장과 유사한 검색 및 바꾸기 기능을 사용했기 때문에 구현 시 비교적 이해하기 쉬운 알고리즘 세트를 직접 작성했습니다. 모바일 개발 기반의 텍스트 검색 및 바꾸기 기능은 기본적으로 PC 세그먼트 메모장의 검색 및 바꾸기 관련 기능을 구현합니다. 기본 기능에는 찾기, 바꾸기, 모두 바꾸기, 실행 취소, 이전 항목, 다음 항목, 색상 표시 및 위치 지정 등이 포함됩니다.
SpannableStringBuilder는 문자열을 저장하기 위해 CharSequence 클래스를 구현합니다. SpannableStringBuilder에는 저장된 문자열에 다양한 형식이나 속성을 추가하고 원본 문자열을 밑줄, 배경색, 글꼴 색상, 클릭 모니터 설정, 하이퍼링크 설정 등과 같은 다양한 스타일로 표시할 수 있는 setSpan() 함수가 있습니다. 가장 중요한 것은 배경색을 설정하는 것입니다. 관심 있는 학생들은 스스로 알아볼 수 있습니다.
알고리즘 찾기
mBinding.tvSeek.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TextUtils.isEmpty(mBinding.etName.getText().toString().trim())) {
showToast("输入查找内容");
return;
}
if (!mBinding.tvContent.getText().toString().contains(mBinding.etName.getText().toString())) {
showToast("查找内容不存在");
listFind = new ArrayList<>();
mBinding.tvNumber.setVisibility(View.INVISIBLE);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(mBinding.tvContent.getText().toString());
BackgroundColorSpan colorSpan;
colorSpan = new BackgroundColorSpan(Color.parseColor("#ffffff"));
spannableStringBuilder.setSpan(colorSpan, 0, mBinding.tvContent.getText().toString().length() - 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mBinding.tvContent.setText(spannableStringBuilder);
return;
}
findKey = mBinding.etName.getText().toString();
listReplace = new ArrayList<>();
mBinding.tvContent.getText().toString().contains(mBinding.etName.getText().toString());
getSubString(mBinding.tvContent.getText().toString(), findKey);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(mBinding.tvContent.getText().toString());
if (listFind != null && listFind.size() != 0) {
for (int i = 0; i < listFind.size(); i++) {
BackgroundColorSpan colorSpan;
if (i == 0) {
colorSpan = new BackgroundColorSpan(Color.parseColor("#f50707"));
} else {
colorSpan = new BackgroundColorSpan(Color.parseColor("#AC00FF30"));
}
spannableStringBuilder.setSpan(colorSpan, listFind.get(i).getStart(), listFind.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
mBinding.tvNumber.setVisibility(View.VISIBLE);
mBinding.tvNumber.setText("查找到" + listFind.size() + "条内容");
} else {
BackgroundColorSpan colorSpan;
colorSpan = new BackgroundColorSpan(Color.parseColor("#212832"));
spannableStringBuilder.setSpan(colorSpan, 0, mBinding.tvContent.getText().length() - 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mBinding.tvNumber.setVisibility(View.INVISIBLE);
}
mBinding.tvContent.setText(spannableStringBuilder);
}
});
포지셔닝 알고리즘 찾기
mBinding.tvPrevious.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listFind != null && listFind.size() != 0) {
if (select > 0) {
select = select - 1;
} else if (select == 0) {
select = listFind.size() - 1;
}
} else {
return;
}
next();
}
});
private void next() {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(mBinding.tvContent.getText().toString());
if (listFind != null && listFind.size() != 0) {
for (int i = 0; i < listFind.size(); i++) {
BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor("#AC00FF30"));
spannableStringBuilder.setSpan(colorSpan, listFind.get(i).getStart(), listFind.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
}
if (listReplace != null && listReplace.size() != 0) {
for (int i = 0; i < listReplace.size(); i++) {
BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor("#f5e107"));
spannableStringBuilder.setSpan(colorSpan, listReplace.get(i).getStart(), listReplace.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
}
BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor("#f50707"));
spannableStringBuilder.setSpan(colorSpan, listFind.get(select).getStart(), listFind.get(select).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mBinding.tvContent.setText(spannableStringBuilder);
mBinding.tvContent.setSelection(listFind.get(select).getStart(), listFind.get(select).getEnd());
}
대체 알고리즘
mBinding.tvReplace.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TextUtils.isEmpty(findKey)) {
showToast("输入查找内容");
return;
}
if (TextUtils.isEmpty(mBinding.etNames.getText().toString())) {
showToast("输入替换内容");
return;
}
replaceKey = mBinding.etNames.getText().toString();
if (listFind != null && listFind.size() != 0) {
if (select <= listFind.size() - 1) {
} else {
select = 0;
}
} else {
showToast("没找到要替换的内容");
return;
}
if (select < listFind.size()) {
} else {
showToast("没找到要替换的内容");
return;
}
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(mBinding.tvContent.getText().toString());
spannableStringBuilder.replace(listFind.get(select).getStart(), listFind.get(select).getEnd(), replaceKey);
FindBean findBean = new FindBean();
findBean.setStart(listFind.get(select).getStart());
findBean.setEnd(listFind.get(select).getStart() + replaceKey.length());
listReplace.add(findBean);
listFind.remove(select);
if (listFind != null && listFind.size() != 0) {
for (int i = 0; i < listFind.size(); i++) {
if (listFind.get(i).getStart() > findBean.getStart()) {
int sub1 = findBean.getEnd() - findBean.getStart();
int sub2 = listFind.get(i).getEnd() - listFind.get(i).getStart();
listFind.get(i).setStart(listFind.get(i).getStart() + sub1 - sub2);
listFind.get(i).setEnd(listFind.get(i).getEnd() + sub1 - sub2);
}
}
}
if (listReplace != null && listReplace.size() != 0) {
for (int i = 0; i < listReplace.size(); i++) {
if (listReplace.get(i).getStart() > findBean.getStart()) {
int sub1 = findBean.getEnd() - findBean.getStart();
listReplace.get(i).setStart(listReplace.get(i).getStart() + sub1 - findKey.length());
listReplace.get(i).setEnd(listReplace.get(i).getEnd() + sub1 - findKey.length());
}
}
}
for (int i = 0; i < listFind.size(); i++) {
BackgroundColorSpan colorSpan;
if (i == select) {
colorSpan = new BackgroundColorSpan(Color.parseColor("#f50707"));
} else {
colorSpan = new BackgroundColorSpan(Color.parseColor("#AC00FF30"));
}
spannableStringBuilder.setSpan(colorSpan, listFind.get(i).getStart(), listFind.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
for (int i = 0; i < listReplace.size(); i++) {
BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor("#f5e107"));
spannableStringBuilder.setSpan(colorSpan, listReplace.get(i).getStart(), listReplace.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
mBinding.tvContent.setText(spannableStringBuilder);
mBinding.tvContent.setSelection(listFind.get(select).getStart(), listFind.get(select).getEnd());
}
});
실행 취소 알고리즘
mBinding.tvUndo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listReplace != null && listReplace.size() != 0) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(mBinding.tvContent.getText().toString());
spannableStringBuilder.replace(listReplace.get(listReplace.size() - 1).getStart(), listReplace.get(listReplace.size() - 1).getEnd(), findKey);
FindBean findBean = new FindBean();
findBean.setStart(listReplace.get(listReplace.size() - 1).getStart());
findBean.setEnd(listReplace.get(listReplace.size() - 1).getStart() + findKey.length());
listFind.add(findBean);
Collections.sort(listFind, new Comparator<FindBean>() {
@Override
public int compare(FindBean o1, FindBean o2) {
int diff = o1.getStart() - o2.getStart();
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
}
return 0; //相等为0
}
});
select = listFind.indexOf(findBean);
listReplace.remove(listReplace.size() - 1);
if (listFind != null && listFind.size() != 0) {
for (int i = 0; i < listFind.size(); i++) {
if (listFind.get(i).getStart() > findBean.getStart()) {
int sub1 = findBean.getEnd() - findBean.getStart();
listFind.get(i).setStart(listFind.get(i).getStart() + sub1 - replaceKey.length());
listFind.get(i).setEnd(listFind.get(i).getEnd() + sub1 - replaceKey.length());
}
}
}
if (listReplace != null && listReplace.size() != 0) {
for (int i = 0; i < listReplace.size(); i++) {
if (listReplace.get(i).getStart() > findBean.getStart()) {
int sub1 = findBean.getEnd() - findBean.getStart();
int sub2 = listReplace.get(i).getEnd() - listReplace.get(i).getStart();
listReplace.get(i).setStart(listReplace.get(i).getStart() + sub1 - sub2);
listReplace.get(i).setEnd(listReplace.get(i).getEnd() + sub1 - sub2);
}
}
}
for (int i = 0; i < listFind.size(); i++) {
BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor("#AC00FF30"));
spannableStringBuilder.setSpan(colorSpan, listFind.get(i).getStart(), listFind.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
for (int i = 0; i < listReplace.size(); i++) {
BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor("#f5e107"));
spannableStringBuilder.setSpan(colorSpan, listReplace.get(i).getStart(), listReplace.get(i).getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
mBinding.tvContent.setText(spannableStringBuilder);
mBinding.tvContent.setSelection(listFind.get(select).getStart(), listFind.get(select).getEnd());
} else {
showToast("撤销完毕");
}
}
});
아래 첨자 위치 개체를 기록합니다.
public class FindBean {
private int start;
private int end;
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
}
구체적인 방법을 이해하려면 데모를 시청하세요. Android + 텍스트 검색 및 바꾸기 + 텍스트에서 검색, 바꾸기, 취소 등이 가능하며 기본적으로 PC 측에서 .txt 검색 및 바꾸기 기능을 구현합니다. - Android 문서 리소스 - CSDN 라이브러리